in source/shared/core_results.cpp [1472:1579]
SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ sqlsrv_buffered_result_set::meta_data& meta,
_In_ zend_long mem_used )
{
SQLSMALLINT extra = 0;
SQLULEN* output_buffer_len = NULL;
// Set the amount of space necessary for null characters at the end of the data.
switch( meta.c_type ) {
case SQL_C_WCHAR:
extra = sizeof( SQLWCHAR );
break;
case SQL_C_BINARY:
extra = 0;
break;
case SQL_C_CHAR:
extra = sizeof( SQLCHAR );
break;
default:
SQLSRV_ASSERT( false, "Invalid type in read_lob_field" );
break;
}
SQLLEN already_read = 0;
SQLLEN to_read = INITIAL_LOB_FIELD_LEN;
sqlsrv_malloc_auto_ptr<char> buffer;
buffer = static_cast<char*>( sqlsrv_malloc( INITIAL_LOB_FIELD_LEN + extra + sizeof( SQLULEN )));
SQLRETURN r = SQL_SUCCESS;
SQLCHAR state[SQL_SQLSTATE_BUFSIZE] = {'\0'};
SQLLEN last_field_len = 0;
bool full_length_returned = false;
do {
output_buffer_len = reinterpret_cast<SQLULEN*>( buffer.get() );
r = core::SQLGetData( stmt, field_index + 1, meta.c_type, buffer.get() + already_read + sizeof( SQLULEN ),
to_read - already_read + extra, &last_field_len, false /*handle_warning*/ );
// if the field is NULL, then return a NULL pointer
if( last_field_len == SQL_NULL_DATA ) {
return NULL;
}
// if the last read was successful, we're done
if( r == SQL_SUCCESS ) {
// check to make sure we haven't overflown our memory limit
CHECK_CUSTOM_ERROR( mem_used + last_field_len > stmt->buffered_query_limit * 1024, stmt,
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) {
throw core::CoreException();
}
break;
}
// else if it wasn't the truncated warning (01004) then we're done
else if( r == SQL_SUCCESS_WITH_INFO ) {
SQLSMALLINT len;
core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len
);
if( !is_truncated_warning( state )) {
break;
}
}
SQLSRV_ASSERT( SQL_SUCCEEDED( r ), "Unknown SQL error not triggered" );
already_read += to_read - already_read;
// if the type of the field returns the total to be read, we use that and preallocate the buffer
if( last_field_len != SQL_NO_TOTAL ) {
CHECK_CUSTOM_ERROR( mem_used + last_field_len > stmt->buffered_query_limit * 1024, stmt,
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) {
throw core::CoreException();
}
to_read = last_field_len;
buffer.resize( to_read + extra + sizeof( SQLULEN ));
output_buffer_len = reinterpret_cast<SQLULEN*>( buffer.get() );
// record the size of the field since we have it available
*output_buffer_len = last_field_len;
full_length_returned = true;
}
// otherwise allocate another chunk of memory to read in
else {
to_read *= 2;
CHECK_CUSTOM_ERROR( mem_used + to_read > stmt->buffered_query_limit * 1024, stmt,
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) {
throw core::CoreException();
}
buffer.resize( to_read + extra + sizeof( SQLULEN ));
output_buffer_len = reinterpret_cast<SQLULEN*>( buffer.get() );
}
} while( true );
SQLSRV_ASSERT( output_buffer_len != NULL, "Output buffer not allocated properly" );
// most LOB field types return the total length in the last_field_len, but some field types such as XML
// only return the amount read on the last read
if( !full_length_returned ) {
*output_buffer_len = already_read + last_field_len;
}
char* return_buffer = buffer;
buffer.transferred();
return return_buffer;
}