title: SQLGetData issues using C++ and SQL Native Client
body: <p>I have a C++ application that uses SQL Native Client to connect to a MS SQL Server 2000.</p>
  
  <p>I am trying to retrieve a result from a TEXT column containing more data than the buffer initially allocated to it provides.  To clarify my issue, I'll outline what I'm doing (code below):</p>
  
  <ol>
  <li>allocate buffer of 1024 bytes use</li>
  <li>bind buffer to column using SQLBindColumn</li>
  <li>execute a SELECT query using SQLExecute</li>
  <li>iterate through results using SQLFetch</li>
  <li>SQLFetch was unable to return the entire result to my buffer: I'd like to use SQLGetData to retrieve the entire column value</li>
  </ol>
  
  <p>The above order of operations presents a problem: SQLGetData does not work on bound columns in my driver.</p>
  
  <p>A working solution is to use the SQL_DATA_AT_EXEC flag as illustrated by the code below.</p>
  
  <p>Begin code:</p>
  
  <pre><code>#include &lt;windows.h&gt;
  
  #include &lt;sql.h&gt;
  #include &lt;sqlext.h&gt;
  #include &lt;sqltypes.h&gt; 
  #include &lt;sqlncli.h&gt;
  
  #include &lt;cstdio&gt;
  #include &lt;string&gt;
  
  const int MAX_CHAR = 1024;
  
  bool test_retcode( RETCODE my_code, const char* my_message )
  {
      bool success = ( my_code == SQL_SUCCESS_WITH_INFO || my_code == SQL_SUCCESS );
      if ( ! success )
      {
          printf( "%s", my_message );
      }
  
      return success;
  }
  
  int main ( )
  {
      SQLHENV EnvironmentHandle;
  
      RETCODE retcode = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &amp;EnvironmentHandle );
      test_retcode( retcode, "SQLAllocHandle(Env) failed!" );
  
      retcode = SQLSetEnvAttr( EnvironmentHandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER );
      test_retcode( retcode, "SQLSetEnvAttr(ODBC version) Failed" );
  
      SQLHDBC ConnHandle;
      retcode = SQLAllocHandle( SQL_HANDLE_DBC, EnvironmentHandle, &amp;ConnHandle );
      test_retcode( retcode, "Could not allocate MS SQL 2000 connection handle." );
  
      SQLSMALLINT driver_out_length;
      retcode = SQLDriverConnect( ConnHandle,
          NULL, // we're not interested in spawning a window
          (SQLCHAR*) "DRIVER={SQL Native Client};SERVER=localhost;UID=username;PWD=password;Database=Test;",
          SQL_NTS,
          NULL,
          0,
          &amp;driver_out_length,
          SQL_DRIVER_NOPROMPT );
      test_retcode( retcode, "SQLConnect() Failed" );
  
      SQLHSTMT StatementHandle;
      retcode = SQLAllocHandle(SQL_HANDLE_STMT, ConnHandle, &amp;StatementHandle);
      test_retcode( retcode, "Failed to allocate SQL Statement handle." );
  
      char* buffer = new char[ MAX_CHAR ];
      SQLINTEGER length = MAX_CHAR - 1;
  
      // -- Bind Block
      retcode = SQLBindCol( StatementHandle, 
          1,
          SQL_C_CHAR,
          (SQLPOINTER) NULL,
          (SQLINTEGER) SQL_DATA_AT_EXEC,
          &amp;length );
  
      test_retcode( retcode, "Failed to bind column." );
      // -- End Bind Block
  
      retcode = SQLExecDirect( StatementHandle, (SQLCHAR*) "SELECT VeryLong FROM LongData", SQL_NTS );
      test_retcode( retcode, "SQLExecDirect failed." );
  
      // -- Fetch Block
      retcode = SQLFetch( StatementHandle );
      if ( retcode != SQL_SUCCESS &amp;&amp; retcode != SQL_SUCCESS_WITH_INFO &amp;&amp; retcode != SQL_NO_DATA )
      {
          printf( "Problem fetching row.\n" );
          return 9;
      }
  
      printf( "Fetched data.  length: %d\n", length );
      // -- End Fetch Block
  
  
      bool sql_success;
      std::string data;
      RETCODE r2;
      do
      {
          r2 = SQLGetData( StatementHandle, 1, SQL_C_CHAR, buffer, MAX_CHAR, &amp;length );
  
          if ( sql_success = test_retcode( r2, "SQLGetData failed." ) )
          {
              data.append( buffer );
          }
          else
          {
              char* err_msg = new char[ MAX_CHAR ];
              SQLSMALLINT req = 1;
              SQLCHAR state[6];
              SQLINTEGER error;
              SQLINTEGER output_length;
  
              int sql_state = SQLGetDiagRec( SQL_HANDLE_STMT, StatementHandle, req, state, &amp;error, (SQLCHAR*) err_msg, (SQLINTEGER) MAX_CHAR, (SQLSMALLINT*) &amp;output_length );
  
              // state is: 07009, error_msg: "[Microsoft][SQL Native Client]Invalid Descriptor Index"
              printf( "%s\n", err_msg );
  
              delete err_msg;
  
              return 9;
          }
      } 
      while ( sql_success &amp;&amp; r2 != SQL_SUCCESS );
  
      printf( "Done.\n" );
  
      return 0;
  }
  </code></pre>