{"id":1136,"date":"2010-07-10T12:23:22","date_gmt":"2010-07-10T10:23:22","guid":{"rendered":"https:\/\/alax.info\/blog\/?p=1136"},"modified":"2010-12-01T03:23:52","modified_gmt":"2010-12-01T01:23:52","slug":"attributed-atl-accessing-blob-with-isequentialstream","status":"publish","type":"post","link":"https:\/\/alax.info\/blog\/1136","title":{"rendered":"Attributed ATL: Accessing BLOB with ISequentialStream"},"content":{"rendered":"<p>Before <a href=\"http:\/\/social.msdn.microsoft.com\/Forums\/en\/vclanguage\/thread\/a74bcacf-e1e3-44c7-994d-3ebb8fe37973\">attributed ATL was deprecated<\/a>, it was a convenient way to access databases using attributed classes on top of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/fk4h509a.aspx\">OLEDB Consumer Templates<\/a>. Does not it look nice?<\/p>\n<pre style=\"color: #000000; background: none repeat scroll 0% 0% #ffffff;\"><span style=\"color: #808030;\">[<\/span>\r\n    db_command<span style=\"color: #808030;\">(<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">SELECT ServerData FROM Server WHERE Server = ?<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span>\r\n<span style=\"color: #808030;\">]<\/span>\r\n<span style=\"color: #800000; font-weight: bold;\">class<\/span> CGetServerData\r\n<span style=\"color: #800080;\">{<\/span>\r\n<span style=\"color: #800000; font-weight: bold;\">public<\/span><span style=\"color: #e34adc;\">:<\/span>\r\n    <span style=\"color: #808030;\">[<\/span> db_param<span style=\"color: #808030;\">(<\/span><span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">)<\/span> <span style=\"color: #808030;\">]<\/span> <span style=\"color: #603000;\">LONG<\/span> m_nServer<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #808030;\">[<\/span> db_column<span style=\"color: #808030;\">(<\/span><span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">,<\/span> length <span style=\"color: #808030;\">=<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">m_nDataLength<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span> <span style=\"color: #808030;\">]<\/span> ISequentialStream<span style=\"color: #808030;\">*<\/span> m_pDataStream<span style=\"color: #800080;\">;<\/span> DBLENGTH m_nDataLength<span style=\"color: #800080;\">;<\/span>\r\n<span style=\"color: #800080;\">}<\/span><span style=\"color: #800080;\">;<\/span><\/pre>\n<p>It worked great with Visual Studio .NET 2003 and it failed to work with later releases. There are <a href=\"http:\/\/www.google.com\/search?q=db_column+ISequentialStream\">questions on internet about the problem<\/a>, but there few answers if any. As I recently had to convert a project from 2003 version of the compiler to Visual Studio 2008, the problem was finally to be resolved.<\/p>\n<p><!--more-->The first problem, and an easier one was that you have to put attribute values in quotes. &#8216;Db_column(1, &#8230;&#8217; has to be &#8220;db_column(&#8220;1&#8221;, &#8230;&#8217; and besides going through code and making changes, it appeared that if earlier implementation managed to distinguish between ordinal column numbers and field names by checking provided argument to be a number or a string, with Visual Studio 2008 one has to provide strings at any time. If the string is a valid integer, the attribute processor will treat it as an ordinal number.<\/p>\n<p>So if you want your code to be both compiled with 2003 and 2008 versions of Visual Studio, you have a puzzle now: you have to use quotes, but version 2003 will no longer treat the argument as ordinal number. Note that version 2003 will keep compiling the code and the problem will only come up on runtime. As eventually in the project of interest support for version 2003 will be dropped, I was not interested in this problem anymore.<\/p>\n<p>The main problem is related to use of ISequentialStream pointer variable as a data field. Again, it worked great with Visual Studio .NET 2003, it no longer did with Visual Studio .NET 2005. First of all, you cannot use this data type anymore, as templates don&#8217;t provide an automatic mapper to OLE DB Type.\u00ef\u00bf\u00bd Instead of ISequentialStream you have to use IUnknown and QueryInterface the provided pointer before use.<\/p>\n<p>This solves compilation problem, but still the code does not work on runtime. An attempt to bind to the column using such accessor results in DB_E_ERRORSOCCURRED (0x80040E21) &#8220;Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.&#8221; A more thorough look gave DBBINDSTATUS_BADBINDINFO (3) for binding to the column of interest.<\/p>\n<p>The cause of the problem is missing DBOBJECT object pointer in the corresponding DBBINDING::pObject field. Why? A general rule for troubleshooting this kind of problem is to enable expanding attributed source code to check what exactly is generated.<\/p>\n<p>The problem is that unlike previous versions of Visual Studio, ATL attributed code provider is no longer generates correct OLEDB template map code for BLOB fields. And this results in incorrectly generated DBBINDING structure, inability to bind to column and as a final result in DB_E_ERRORSOCCURRED error code which does not give a sufficient clue on the root of the problem.<\/p>\n<p>While the map needs a BLOB_* macro for the BLOB column (e.g. BLOB_ENTRY or <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/w3k8764c.aspx\">BLOB_ENTRY_LENGTH<\/a>), the generated code uses _COLUMN_ENTRY_CODE instead. This causes missing (null) DBBINDING::pObject field in the binding structure:<\/p>\n<pre style=\"color: #000000; background: none repeat scroll 0% 0% #ffffff;\">BEGIN_ACCESSOR_MAP<span style=\"color: #808030;\">(<\/span>_CGetServerDataAccessor<span style=\"color: #808030;\">,<\/span> <span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">)<\/span>\r\n    BEGIN_ACCESSOR<span style=\"color: #808030;\">(<\/span><span style=\"color: #008c00;\">0<\/span><span style=\"color: #808030;\">,<\/span> <span style=\"color: #800000; font-weight: bold;\">true<\/span><span style=\"color: #808030;\">)<\/span>\r\n        <span style=\"color: #696969;\">\/\/_COLUMN_ENTRY_CODE(1, DBTYPE_IUNKNOWN, _SIZE_TYPE(m_pDataUnknown), 0, 0, offsetbuf(m_pDataUnknown), offsetbuf(m_nDataLength), 0)<\/span>\r\n        BLOB_ENTRY_LENGTH<span style=\"color: #808030;\">(<\/span><span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">,<\/span> <span style=\"color: #800000; font-weight: bold;\">__uuidof<\/span><span style=\"color: #808030;\">(<\/span>ISequentialStream<span style=\"color: #808030;\">)<\/span><span style=\"color: #808030;\">,<\/span> STGM_READ<span style=\"color: #808030;\">,<\/span> m_pDataUnknown<span style=\"color: #808030;\">,<\/span> m_nDataLength<span style=\"color: #808030;\">)<\/span>\r\n    END_ACCESSOR<span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">)<\/span>\r\nEND_ACCESSOR_MAP<span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">)<\/span><\/pre>\n<p>So it appears that to fix the problem, an attributed class needs to be replaced with a non-attributed update. To ease the conversion one can expand attributed source and use it as a base for the non-attributed class.<\/p>\n<p>And example of such correction\/replacement is provided below for a reference.<\/p>\n<pre style=\"color: #000000; background: none repeat scroll 0% 0% #ffffff;\"><span style=\"color: #004a43;\">#<\/span><span style=\"color: #004a43;\">if<\/span><span style=\"color: #004a43;\"> TRUE<\/span>\r\n<span style=\"color: #800000; font-weight: bold;\">class<\/span> _CGetServerDataAccessor\r\n<span style=\"color: #800080;\">{<\/span>\r\n<span style=\"color: #800000; font-weight: bold;\">public<\/span><span style=\"color: #e34adc;\">:<\/span>\r\n\r\nDEFINE_COMMAND_EX<span style=\"color: #808030;\">(<\/span>_CGetServerDataAccessor<span style=\"color: #808030;\">,<\/span> <span style=\"color: #800000;\">L\"<\/span><span style=\"color: #0000e6;\">SELECT Data FROM Server WHERE Server = ?<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span>\r\n\r\nBEGIN_PARAM_MAP<span style=\"color: #808030;\">(<\/span>_CGetServerDataAccessor<span style=\"color: #808030;\">)<\/span>\r\n    SET_PARAM_TYPE<span style=\"color: #808030;\">(<\/span>DBPARAMIO_INPUT<span style=\"color: #808030;\">)<\/span>\r\n    <span style=\"color: #696969;\">\/\/_COLUMN_ENTRY_CODE(1, _OLEDB_TYPE(m_nServer), _SIZE_TYPE(m_nServer), 0, 0, offsetbuf(m_nServer), 0, 0)<\/span>\r\n    COLUMN_ENTRY<span style=\"color: #808030;\">(<\/span><span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">,<\/span> m_nServer<span style=\"color: #808030;\">)<\/span>\r\nEND_PARAM_MAP<span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">)<\/span>\r\n\r\nBEGIN_ACCESSOR_MAP<span style=\"color: #808030;\">(<\/span>_CGetServerDataAccessor<span style=\"color: #808030;\">,<\/span> <span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">)<\/span>\r\n    BEGIN_ACCESSOR<span style=\"color: #808030;\">(<\/span><span style=\"color: #008c00;\">0<\/span><span style=\"color: #808030;\">,<\/span> <span style=\"color: #800000; font-weight: bold;\">true<\/span><span style=\"color: #808030;\">)<\/span>\r\n        <span style=\"color: #696969;\">\/\/_COLUMN_ENTRY_CODE(1, DBTYPE_IUNKNOWN, _SIZE_TYPE(m_pDataUnknown), 0, 0, offsetbuf(m_pDataUnknown), offsetbuf(m_nDataLength), 0)<\/span>\r\n        BLOB_ENTRY_LENGTH<span style=\"color: #808030;\">(<\/span><span style=\"color: #008c00;\">1<\/span><span style=\"color: #808030;\">,<\/span> <span style=\"color: #800000; font-weight: bold;\">__uuidof<\/span><span style=\"color: #808030;\">(<\/span>ISequentialStream<span style=\"color: #808030;\">)<\/span><span style=\"color: #808030;\">,<\/span> STGM_READ<span style=\"color: #808030;\">,<\/span> m_pDataUnknown<span style=\"color: #808030;\">,<\/span> m_nDataLength<span style=\"color: #808030;\">)<\/span>\r\n    END_ACCESSOR<span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">)<\/span>\r\nEND_ACCESSOR_MAP<span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">)<\/span>\r\n\r\n<span style=\"color: #800000; font-weight: bold;\">public<\/span><span style=\"color: #e34adc;\">:<\/span>\r\n    <span style=\"color: #603000;\">LONG<\/span> m_nServer<span style=\"color: #800080;\">;<\/span>\r\n    IUnknown<span style=\"color: #808030;\">*<\/span> m_pDataUnknown<span style=\"color: #800080;\">;<\/span>\r\n    DBLENGTH m_nDataLength<span style=\"color: #800080;\">;<\/span>\r\n<span style=\"color: #800080;\">}<\/span><span style=\"color: #800080;\">;<\/span>\r\n\r\n<span style=\"color: #800000; font-weight: bold;\">class<\/span> CGetServerData <span style=\"color: #800080;\">:<\/span>\r\n    <span style=\"color: #800000; font-weight: bold;\">public<\/span> CCommand<span style=\"color: #800080;\">&lt;<\/span>CAccessor<span style=\"color: #800080;\">&lt;<\/span>_CGetServerDataAccessor<span style=\"color: #800080;\">&gt;<\/span> <span style=\"color: #800080;\">&gt;<\/span>\r\n<span style=\"color: #800080;\">{<\/span>\r\n<span style=\"color: #800000; font-weight: bold;\">public<\/span><span style=\"color: #e34adc;\">:<\/span>\r\n<span style=\"color: #696969;\">\/\/ CGetServerData<\/span>\r\n    HRESULT OpenRowset<span style=\"color: #808030;\">(<\/span><span style=\"color: #800000; font-weight: bold;\">const<\/span> CSession<span style=\"color: #808030;\">&amp;<\/span> Session<span style=\"color: #808030;\">,<\/span> <span style=\"color: #603000;\">LPCWSTR<\/span> pszCommand <span style=\"color: #808030;\">=<\/span> <span style=\"color: #7d0045;\">NULL<\/span><span style=\"color: #808030;\">)<\/span> <span style=\"color: #800000; font-weight: bold;\">throw<\/span><span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">)<\/span>\r\n    <span style=\"color: #800080;\">{<\/span>\r\n        <span style=\"color: #800000; font-weight: bold;\">if<\/span><span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">!<\/span>pszCommand<span style=\"color: #808030;\">)<\/span>\r\n            _V<span style=\"color: #808030;\">(<\/span>_CGetServerDataAccessor<span style=\"color: #800080;\">::<\/span>GetDefaultCommand<span style=\"color: #808030;\">(<\/span><span style=\"color: #808030;\">&amp;<\/span>pszCommand<span style=\"color: #808030;\">)<\/span><span style=\"color: #808030;\">)<\/span><span style=\"color: #800080;\">;<\/span>\r\n        <span style=\"color: #800000; font-weight: bold;\">return<\/span> Open<span style=\"color: #808030;\">(<\/span>Session<span style=\"color: #808030;\">,<\/span> pszCommand<span style=\"color: #808030;\">,<\/span> <span style=\"color: #7d0045;\">NULL<\/span><span style=\"color: #808030;\">)<\/span><span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #800080;\">}<\/span>\r\n<span style=\"color: #800080;\">}<\/span><span style=\"color: #800080;\">;<\/span>\r\n<span style=\"color: #004a43;\">#<\/span><span style=\"color: #004a43;\">else<\/span>\r\n<span style=\"color: #808030;\">[<\/span>\r\n    db_command<span style=\"color: #808030;\">(<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">SELECT Data FROM Server WHERE Server = ?<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span>\r\n<span style=\"color: #808030;\">]<\/span>\r\n<span style=\"color: #800000; font-weight: bold;\">class<\/span> CGetServerData\r\n<span style=\"color: #800080;\">{<\/span>\r\n<span style=\"color: #800000; font-weight: bold;\">public<\/span><span style=\"color: #e34adc;\">:<\/span>\r\n    <span style=\"color: #808030;\">[<\/span> db_param<span style=\"color: #808030;\">(<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">1<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span> <span style=\"color: #808030;\">]<\/span> <span style=\"color: #603000;\">LONG<\/span> m_nServer<span style=\"color: #800080;\">;<\/span>\r\n    <span style=\"color: #808030;\">[<\/span> db_column<span style=\"color: #808030;\">(<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">1<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">,<\/span> length <span style=\"color: #808030;\">=<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #0000e6;\">m_nDataLength<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #808030;\">)<\/span> <span style=\"color: #808030;\">]<\/span> IUnknown<span style=\"color: #808030;\">*<\/span> m_pDataUnknown<span style=\"color: #800080;\">;<\/span> DBLENGTH m_nDataLength<span style=\"color: #800080;\">;<\/span>\r\n<span style=\"color: #800080;\">}<\/span><span style=\"color: #800080;\">;<\/span>\r\n<span style=\"color: #004a43;\">#<\/span><span style=\"color: #004a43;\">endif<\/span><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Before attributed ATL was deprecated, it was a convenient way to access databases using attributed classes on top of OLEDB Consumer Templates. Does not it look nice? [ db_command(&#8220;SELECT ServerData FROM Server WHERE Server = ?&#8221;) ] class CGetServerData { public: [ db_param(1) ] LONG m_nServer; [ db_column(1, length = &#8220;m_nDataLength&#8221;) ] ISequentialStream* m_pDataStream; DBLENGTH&hellip; <\/p>\n<p><a class=\"moretag\" href=\"https:\/\/alax.info\/blog\/1136\">Read the full article<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,21],"tags":[487,296,38,295,58],"class_list":["post-1136","post","type-post","status-publish","format-standard","hentry","category-atl","category-seriously","tag-atl","tag-blob","tag-c","tag-template","tag-visual-studio"],"_links":{"self":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/1136","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/comments?post=1136"}],"version-history":[{"count":0,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/1136\/revisions"}],"wp:attachment":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/media?parent=1136"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/categories?post=1136"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/tags?post=1136"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}