23 #define sqlStatusOK( status ) \
24 ( ( status ) == SQL_SUCCESS || ( status ) == SQL_SUCCESS_WITH_INFO )
39 #define SQL_QUERY_BUFSIZE ( MAX_SQL_QUERY_SIZE + 64 )
48 #define VALUE_TO_PTR ULongToPtr
50 #define VALUE_TO_PTR ( SQLPOINTER )
61 SQL_TIMESTAMP_STRUCT timestampStorage;
91 static INSTANCE_HANDLE hODBC = NULL_INSTANCE;
94 ( SQLSMALLINT HandleType,
IN SQLHANDLE InputHandle,
95 OUT_PTR SQLHANDLE *OutputHandlePtr );
97 (
IN SQLHSTMT StatementHandle,
98 SQLUSMALLINT ParameterNumber, SQLSMALLINT InputOutputType,
99 SQLSMALLINT ValueType, SQLSMALLINT ParameterType,
100 SQLUINTEGER ColumnSize, SQLSMALLINT DecimalDigits,
102 SQLINTEGER BufferLength,
103 INOUT_OPT SQLINTEGER *StrLen_or_IndPtr );
104 typedef SQLRETURN ( SQL_API *SQLCLOSECURSOR )(
IN SQLHSTMT StatementHandle );
106 (
IN SQLHDBC ConnectionHandle,
107 IN_BUFFER( NameLength1 ) SQLCHAR *ServerName,
108 SQLSMALLINT NameLength1,
109 IN_BUFFER( NameLength2 ) SQLCHAR *UserName,
110 SQLSMALLINT NameLength2,
111 IN_BUFFER( NameLength3 ) SQLCHAR *Authentication,
112 SQLSMALLINT NameLength3 );
113 typedef SQLRETURN ( SQL_API *SQLDISCONNECT )(
IN SQLHDBC ConnectionHandle );
114 typedef SQLRETURN ( SQL_API *SQLENDTRAN )( SQLSMALLINT HandleType,
115 IN SQLHANDLE Handle, SQLSMALLINT CompletionType );
117 ( SQLHSTMT StatementHandle,
118 IN_BUFFER( TextLength ) SQLCHAR *StatementText,
119 SQLINTEGER TextLength );
121 (
IN SQLHSTMT StatementHandle );
123 (
IN SQLHSTMT StatementHandle );
124 typedef SQLRETURN ( SQL_API *SQLFREEHANDLE )( SQLSMALLINT HandleType,
125 IN SQLHANDLE Handle );
127 ( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,
128 SQLSMALLINT TargetType,
129 OUT_BUFFER( BufferLength, *StrLen_or_IndPtr ) \
130 SQLPOINTER TargetValuePtr,
131 SQLINTEGER BufferLength, SQLINTEGER *StrLen_or_IndPtr );
133 ( SQLSMALLINT HandleType,
134 IN SQLHANDLE Handle, SQLSMALLINT RecNumber,
136 OUT SQLINTEGER *NativeErrorPtr,
138 SQLCHAR *MessageText,
139 SQLSMALLINT BufferLength, SQLSMALLINT *TextLengthPtr );
141 (
IN SQLHDBC ConnectionHandle,
142 SQLUSMALLINT InfoType,
143 OUT_BUFFER( BufferLength, *StringLengthPtr ) \
144 SQLPOINTER InfoValuePtr,
145 SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr );
147 (
IN SQLHSTMT StatementHandle,
148 SQLINTEGER Attribute,
OUT SQLPOINTER ValuePtr,
149 SQLINTEGER BufferLength,
152 (
IN SQLHSTMT StatementHandle,
153 SQLSMALLINT DataType );
155 (
IN SQLHSTMT StatementHandle,
156 IN_BUFFER( TextLength ) SQLCHAR *StatementText,
157 SQLINTEGER TextLength );
159 (
IN SQLHSTMT StatementHandle,
160 OUT SQLINTEGER *RowCountPtr );
162 (
IN SQLHDBC ConnectionHandle,
163 SQLINTEGER Attribute, SQLPOINTER ValuePtr,
164 SQLINTEGER StringLength );
166 (
IN SQLHENV EnvironmentHandle,
167 SQLINTEGER Attribute, SQLPOINTER ValuePtr,
168 SQLINTEGER StringLength );
170 (
IN SQLHSTMT StatementHandle,
171 SQLINTEGER Attribute, SQLPOINTER ValuePtr,
172 SQLINTEGER StringLength );
174 static SQLALLOCHANDLE pSQLAllocHandle = NULL;
175 static SQLBINDPARAMETER pSQLBindParameter = NULL;
176 static SQLCLOSECURSOR pSQLCloseCursor = NULL;
177 static SQLCONNECT pSQLConnect = NULL;
178 static SQLDISCONNECT pSQLDisconnect = NULL;
179 static SQLENDTRAN pSQLEndTran = NULL;
180 static SQLEXECDIRECT pSQLExecDirect = NULL;
181 static SQLEXECUTE pSQLExecute = NULL;
182 static SQLFETCH pSQLFetch = NULL;
183 static SQLFREEHANDLE pSQLFreeHandle = NULL;
184 static SQLGETDATA pSQLGetData = NULL;
185 static SQLGETDIAGREC pSQLGetDiagRec = NULL;
186 static SQLGETINFO pSQLGetInfo = NULL;
187 static SQLGETSTMTATTR pSQLGetStmtAttr = NULL;
188 static SQLGETTYPEINFO pSQLGetTypeInfo = NULL;
189 static SQLPREPARE pSQLPrepare = NULL;
190 static SQLROWCOUNT_FN pSQLRowCount = NULL;
191 static SQLSETCONNECTATTR pSQLSetConnectAttr = NULL;
192 static SQLSETENVATTR pSQLSetEnvAttr = NULL;
193 static SQLSETSTMTATTR pSQLSetStmtAttr = NULL;
200 #define SQLAllocHandle pSQLAllocHandle
201 #define SQLBindParameter pSQLBindParameter
202 #define SQLCloseCursor pSQLCloseCursor
203 #define SQLConnect pSQLConnect
204 #define SQLDisconnect pSQLDisconnect
205 #define SQLEndTran pSQLEndTran
206 #define SQLExecDirect pSQLExecDirect
207 #define SQLExecute pSQLExecute
208 #define SQLFetch pSQLFetch
209 #define SQLFreeHandle pSQLFreeHandle
210 #define SQLGetData pSQLGetData
211 #define SQLGetDiagRec pSQLGetDiagRec
212 #define SQLGetInfo pSQLGetInfo
213 #define SQLGetStmtAttr pSQLGetStmtAttr
214 #define SQLGetTypeInfo pSQLGetTypeInfo
215 #define SQLPrepare pSQLPrepare
216 #define SQLRowCount pSQLRowCount
217 #define SQLSetConnectAttr pSQLSetConnectAttr
218 #define SQLSetEnvAttr pSQLSetEnvAttr
219 #define SQLSetStmtAttr pSQLSetStmtAttr
224 #if defined( __WIN16__ )
225 #define ODBC_LIBNAME "ODBC.DLL"
226 #elif defined( __WIN32__ )
227 #define ODBC_LIBNAME "ODBC32.DLL"
228 #elif defined( __UNIX__ )
229 #if defined( __APPLE__ )
231 #define ODBC_LIBNAME "libiodbc.dylib"
237 #define ODBC_LIBNAME "libodbc.so"
238 #define ODBC_ALT_LIBNAME "libiodbc.so"
252 if( hODBC != NULL_INSTANCE )
256 #if defined( __WIN16__ )
257 errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
258 hODBC = LoadLibrary( ODBC_LIBNAME );
259 SetErrorMode( errorMode );
260 if( hODBC < HINSTANCE_ERROR )
262 hODBC = NULL_INSTANCE;
265 #elif defined( __UNIX__ ) && !defined( __APPLE__ )
266 if( ( hODBC = DynamicLoad( ODBC_LIBNAME ) ) == NULL_INSTANCE && \
267 ( hODBC = DynamicLoad( ODBC_ALT_LIBNAME ) ) == NULL_INSTANCE )
270 if( ( hODBC = DynamicLoad( ODBC_LIBNAME ) ) == NULL_INSTANCE )
275 pSQLAllocHandle = ( SQLALLOCHANDLE ) DynamicBind( hODBC,
"SQLAllocHandle" );
276 pSQLBindParameter = ( SQLBINDPARAMETER ) DynamicBind( hODBC,
"SQLBindParameter" );
277 pSQLCloseCursor = ( SQLCLOSECURSOR ) DynamicBind( hODBC,
"SQLCloseCursor" );
278 pSQLConnect = ( SQLCONNECT ) DynamicBind( hODBC,
"SQLConnect" );
279 pSQLDisconnect = ( SQLDISCONNECT ) DynamicBind( hODBC,
"SQLDisconnect" );
280 pSQLEndTran = ( SQLENDTRAN ) DynamicBind( hODBC,
"SQLEndTran" );
281 pSQLExecDirect = ( SQLEXECDIRECT ) DynamicBind( hODBC,
"SQLExecDirect" );
282 pSQLExecute = ( SQLEXECUTE ) DynamicBind( hODBC,
"SQLExecute" );
283 pSQLFetch = ( SQLFETCH ) DynamicBind( hODBC,
"SQLFetch" );
284 pSQLFreeHandle = ( SQLFREEHANDLE ) DynamicBind( hODBC,
"SQLFreeHandle" );
285 pSQLGetData = ( SQLGETDATA ) DynamicBind( hODBC,
"SQLGetData" );
286 pSQLGetDiagRec = ( SQLGETDIAGREC ) DynamicBind( hODBC,
"SQLGetDiagRec" );
287 pSQLGetInfo = ( SQLGETINFO ) DynamicBind( hODBC,
"SQLGetInfo" );
288 pSQLGetStmtAttr = ( SQLGETSTMTATTR ) DynamicBind( hODBC,
"SQLGetStmtAttr" );
289 pSQLGetTypeInfo = ( SQLGETTYPEINFO ) DynamicBind( hODBC,
"SQLGetTypeInfo" );
290 pSQLPrepare = ( SQLPREPARE ) DynamicBind( hODBC,
"SQLPrepare" );
291 pSQLRowCount = ( SQLROWCOUNT_FN ) DynamicBind( hODBC,
"SQLRowCount" );
292 pSQLSetConnectAttr = ( SQLSETCONNECTATTR ) DynamicBind( hODBC,
"SQLSetConnectAttr" );
293 pSQLSetEnvAttr = ( SQLSETENVATTR ) DynamicBind( hODBC,
"SQLSetEnvAttr" );
294 pSQLSetStmtAttr = ( SQLSETSTMTATTR ) DynamicBind( hODBC,
"SQLSetStmtAttr" );
297 if( pSQLAllocHandle == NULL || pSQLBindParameter == NULL ||
298 pSQLCloseCursor == NULL || pSQLConnect == NULL ||
299 pSQLDisconnect == NULL || pSQLEndTran == NULL ||
300 pSQLExecDirect == NULL || pSQLExecute == NULL ||
301 pSQLFetch == NULL || pSQLFreeHandle == NULL ||
302 pSQLGetData == NULL || pSQLGetDiagRec == NULL ||
303 pSQLGetInfo == NULL || pSQLGetStmtAttr == NULL ||
304 pSQLGetTypeInfo == NULL || pSQLPrepare == NULL ||
305 pSQLSetConnectAttr == NULL || pSQLSetEnvAttr == NULL ||
306 pSQLSetStmtAttr == NULL )
309 DynamicUnload( hODBC );
310 hODBC = NULL_INSTANCE;
319 if( hODBC != NULL_INSTANCE )
320 DynamicUnload( hODBC );
321 hODBC = NULL_INSTANCE;
349 const SQLHSTMT hStmt,
355 char szSqlState[ SQL_SQLSTATE_SIZE + 8 ];
358 SQLINTEGER dwNativeError = 0;
359 SQLSMALLINT handleType, errorStringLength;
374 handleType = SQL_HANDLE_STMT;
379 handleType = SQL_HANDLE_DBC;
380 handle = dbmsInfo->hDbc;
384 handleType = SQL_HANDLE_ENV;
385 handle = dbmsInfo->hEnv;
394 sqlStatus = SQLGetDiagRec( handleType, handle, 1, szSqlState,
396 &errorStringLength );
401 sqlStatus = SQLGetDiagRec( SQL_HANDLE_DBC, dbmsInfo->hDbc, 1,
402 szSqlState, &dwNativeError,
404 &errorStringLength );
408 DEBUG_DIAG((
"Couldn't read error information from database "
412 "Couldn't get error information from database "
419 if( errorStringLength > 0 )
429 if( !memcmp( szSqlState,
"S0002", 5 ) ||
430 !memcmp( szSqlState,
"42S02", 5 ) ||
431 ( !memcmp( szSqlState,
"00000", 5 ) && \
432 sqlStatus == SQL_NO_DATA ) )
436 if( errorStringLength <= 0 )
448 if( !memcmp( szSqlState,
"S0001", 5 ) ||
449 !memcmp( szSqlState,
"S0011", 5 ) ||
450 !memcmp( szSqlState,
"42S01", 5 ) ||
451 !memcmp( szSqlState,
"42S11", 5 ) )
460 if( !memcmp( szSqlState,
"23000", 5 ) )
463 return( defaultStatus );
478 const char *newSubString,
481 const int remainder = origStringLength - subStringLength;
482 const int newStringLength = newSubStringLength + remainder;
484 assert(
isWritePtr(
string, stringMaxLength ) );
485 assert(
isReadPtr( newSubString, newSubStringLength ) );
489 subStringLength < origStringLength && \
492 origStringLength <= stringMaxLength && \
494 REQUIRES( newSubStringLength > 0 && \
502 ENSURES( remainder > 0 && newStringLength > 0 && \
503 newStringLength < stringMaxLength );
516 memmove(
string + newSubStringLength,
string + subStringLength,
518 memcpy(
string, newSubString, newSubStringLength );
519 *stringLength = newSubStringLength - subStringLength;
526 OUT_BUFFER( queryMaxLen, *queryLength )
char *query,
529 IN_BUFFER( commandLength )
const char *command,
532 int currentLength = commandLength;
537 assert(
isReadPtr( command, commandLength ) );
540 REQUIRES( commandLength > 0 && commandLength < queryMaxLen && \
547 memcpy( query, command, commandLength );
551 if( !
strCompare( command,
"CREATE TABLE", 12 ) )
553 offset =
strFindStr( query, currentLength,
" BLOB", 5 );
558 status = rewriteString( query + offset, queryMaxLen - offset,
559 &length, 4, currentLength - offset,
561 dbmsInfo->blobNameLength );
566 offset =
strFindStr( query, currentLength,
" DATETIME", 9 );
568 !( dbmsInfo->dateTimeNameLength == 8 && \
569 !
strCompare( dbmsInfo->dateTimeName,
"DATETIME", 8 ) ) )
572 status = rewriteString( query + offset, queryMaxLen - offset,
573 &length, 8, currentLength - offset,
574 dbmsInfo->dateTimeName,
575 dbmsInfo->dateTimeNameLength );
584 switch( dbmsInfo->backendType )
591 strFindStr( query, currentLength,
" LIKE ", 6 ) <= 7 )
593 *queryLength = currentLength;
601 if(
strCompare( query,
"CREATE TABLE", 12 ) && \
606 *queryLength = currentLength;
609 if(
strFindStr( query, currentLength,
" type ", 6 ) <= 7 )
611 *queryLength = currentLength;
618 *queryLength = currentLength;
626 ( offset =
strFindStr( query, currentLength,
" LIKE ", 6 ) ) > 0 )
635 for( i = offset + 7; i < offset + 11 && i < currentLength; i++ )
637 if( query[ i ] ==
'%' )
645 ( offset =
strFindStr( query, currentLength,
" type ", 6 ) ) > 0 )
648 status = rewriteString( query + offset, queryMaxLen - offset,
649 &length, 4, currentLength - offset,
656 *queryLength = currentLength;
665 static
int bindParameters(
const SQLHSTMT hStmt,
668 INOUT BOUND_DATA_STATE *boundDataState,
671 SQLUSMALLINT paramNo = 1;
676 assert(
isWritePtr( boundDataState,
sizeof( BOUND_DATA_STATE ) ) );
683 const BOUND_DATA *boundDataPtr = &boundData[ i ];
684 SQLSMALLINT valueType, parameterType;
689 SQL_TIMESTAMP_STRUCT *timestampStorage = \
690 &boundDataState->timestampStorage;
691 struct tm timeInfo, *timeInfoPtr = &timeInfo;
696 timeInfoPtr =
gmTime_s( boundDataPtr->data, timeInfoPtr );
697 if( timeInfoPtr == NULL )
709 memset( timestampStorage, 0,
sizeof( SQL_TIMESTAMP_STRUCT ) );
710 timestampStorage->year = ( SQLSMALLINT ) ( timeInfoPtr->tm_year + 1900 );
711 timestampStorage->month = ( SQLUSMALLINT ) ( timeInfoPtr->tm_mon + 1 );
712 timestampStorage->day = ( SQLUSMALLINT ) timeInfoPtr->tm_mday;
713 timestampStorage->hour = ( SQLUSMALLINT ) timeInfoPtr->tm_hour;
714 timestampStorage->minute = ( SQLUSMALLINT ) timeInfoPtr->tm_min;
715 timestampStorage->second = ( SQLUSMALLINT ) timeInfoPtr->tm_sec;
716 sqlStatus = SQLBindParameter( hStmt, paramNo++, SQL_PARAM_INPUT,
717 SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP,
718 dbmsInfo->dateTimeNameColSize, 0,
719 timestampStorage, 0, NULL );
726 assert( ( boundDataPtr->
dataLength == 0 ) || \
731 REQUIRES( dbmsInfo->hasBinaryBlobs || \
732 ( !dbmsInfo->hasBinaryBlobs && \
734 REQUIRES( ( boundDataPtr == NULL ) || \
735 ( boundDataPtr != NULL && \
736 ( boundDataPtr->data == NULL && \
738 ( boundDataPtr->data != NULL && \
749 static const SQLINTEGER nullDataValue = SQL_NULL_DATA;
751 sqlStatus = SQLBindParameter( hStmt, paramNo++, SQL_PARAM_INPUT,
752 SQL_C_CHAR, SQL_C_CHAR, 1, 0, NULL, 0,
753 ( SQLINTEGER * ) &nullDataValue );
763 valueType = SQL_C_BINARY;
764 parameterType = dbmsInfo->blobType;
767 valueType = parameterType = SQL_C_CHAR;
768 boundDataState->lengthStorage[ i ] = boundDataPtr->
dataLength;
769 sqlStatus = SQLBindParameter( hStmt, paramNo++, SQL_PARAM_INPUT,
770 valueType, parameterType,
772 ( SQLPOINTER ) boundDataPtr->data,
774 &boundDataState->lengthStorage[ i ] );
796 const SQLSMALLINT
type,
801 SQLINTEGER blobNameLength, count,
dummy;
811 sqlStatus = SQLGetTypeInfo( hStmt, type );
813 sqlStatus = SQLFetch( hStmt );
820 SQLGetData( hStmt, 1, SQL_C_CHAR, dbmsInfo->blobName,
822 sqlStatus = SQLGetData( hStmt, 3, SQL_C_SLONG, &count,
823 sizeof( SQLINTEGER ), &dummy );
824 SQLCloseCursor( hStmt );
827 if( dbmsInfo->backendType ==
DBMS_MYSQL && blobNameLength == 0 )
833 blobNameLength = strlen( dbmsInfo->blobName );
835 dbmsInfo->blobNameLength = ( int ) blobNameLength;
837 if( dummy !=
sizeof( SQLINTEGER ) )
839 fprintf( stderr,
"\ncryptlib: The ODBC driver is erroneously "
840 "returning a %ld-byte integer value\n when a "
841 "%d-byte SQLINTEGER value is requested, which will "
842 "overwrite\n adjacent memory locations. To fix "
843 "this you need to recompile\n with whatever "
844 "preprocessor options your ODBC header files require\n"
845 " to force the use of 64-bit ODBC data types (and "
846 "report this issue\n to the ODBC driver vendor so "
847 "that they can sync the driver and\n headers)."
848 "\n\n", (
long ) dummy,
sizeof( SQLINTEGER ) );
851 *maxFieldSize = count;
861 if( ( type == SQL_LONGVARBINARY ) && \
863 dbmsInfo->hasBinaryBlobs =
TRUE;
864 dbmsInfo->blobType =
type;
874 SQLINTEGER dateTimeNameLength, columnSize,
dummy;
882 memcpy( dbmsInfo->dateTimeName,
"TIMESTAMP", 9 );
883 dbmsInfo->dateTimeNameLength = 9;
884 dbmsInfo->dateTimeNameColSize = 16;
893 sqlStatus = SQLGetTypeInfo( hStmt, SQL_TYPE_TIMESTAMP );
896 DEBUG_DIAG((
"Database backend uses pre-ODBC 3.0 data types" ));
898 sqlStatus = SQLGetTypeInfo( hStmt, SQL_TIMESTAMP );
905 sqlStatus = SQLFetch( hStmt );
908 SQLCloseCursor( hStmt );
911 sqlStatus = SQLGetData( hStmt, 1, SQL_C_CHAR, dbmsInfo->dateTimeName,
914 sqlStatus = SQLGetData( hStmt, 3, SQL_C_SLONG,
915 &dbmsInfo->dateTimeNameColSize,
916 sizeof( SQLINTEGER ), &dummy );
919 SQLCloseCursor( hStmt );
922 if( dbmsInfo->backendType ==
DBMS_MYSQL && dateTimeNameLength == 0 )
928 dateTimeNameLength = strlen( dbmsInfo->dateTimeName );
930 dbmsInfo->dateTimeNameLength = ( int ) dateTimeNameLength;
946 if( dbmsInfo->dateTimeNameColSize != 16 )
949 SQLCloseCursor( hStmt );
956 sqlStatus = SQLFetch( hStmt );
959 SQLCloseCursor( hStmt );
962 sqlStatus = SQLGetData( hStmt, 3, SQL_C_SLONG, &columnSize,
963 sizeof( SQLINTEGER ), &dummy );
965 dbmsInfo->dateTimeNameColSize = columnSize;
966 SQLCloseCursor( hStmt );
981 SQLUSMALLINT transactBehaviour;
982 SQLINTEGER attrLength;
983 SQLUINTEGER privileges;
988 assert(
isWritePtr( featureFlags,
sizeof(
int ) ) );
995 status = getBlobInfo( dbmsInfo, SQL_LONGVARBINARY, &maxBlobSize );
997 status = getBlobInfo( dbmsInfo, SQL_LONGVARCHAR, &maxBlobSize );
1001 if( dbmsInfo->hasBinaryBlobs )
1008 char errorMessage[ 128 + 8 ];
1009 int errorMessageLength;
1011 errorMessageLength = \
1012 sprintf_s( errorMessage, 128,
1013 "Database blob type can only store %d bytes, we need "
1028 sqlStatus = SQLGetStmtAttr( hStmt, SQL_ATTR_MAX_LENGTH,
1029 ( SQLPOINTER ) &attrLength, SQL_IS_INTEGER,
1034 char errorMessage[ 128 + 8 ];
1035 int errorMessageLength;
1037 errorMessageLength = \
1038 sprintf_s( errorMessage, 128,
1039 "Database back-end can only transmit %d bytes per "
1040 "message, we need at least %d", attrLength,
1047 status = getDateTimeInfo( dbmsInfo );
1054 sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_DATA_SOURCE_READ_ONLY,
1055 buffer, 8, &bufLen );
1070 sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_SQL92_GRANT,
1071 ( SQLPOINTER ) &privileges,
1072 sizeof( SQLUINTEGER ), &bufLen );
1075 sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_SQL92_REVOKE,
1076 ( SQLPOINTER ) &privileges,
1077 sizeof( SQLUINTEGER ), &bufLen );
1092 sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_CURSOR_COMMIT_BEHAVIOR,
1093 &transactBehaviour,
sizeof( SQLUSMALLINT ),
1095 if(
sqlStatusOK( sqlStatus ) && transactBehaviour == SQL_CB_DELETE )
1097 DEBUG_DIAG((
"Database uses destructive transactions" ));
1099 dbmsInfo->transactIsDestructive =
TRUE;
1101 sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_CURSOR_ROLLBACK_BEHAVIOR,
1102 &transactBehaviour,
sizeof( SQLUSMALLINT ),
1104 if(
sqlStatusOK( sqlStatus ) && transactBehaviour == SQL_CB_DELETE )
1106 DEBUG_DIAG((
"Database uses destructive transactions" ));
1108 dbmsInfo->transactIsDestructive =
TRUE;
1120 SQLRETURN sqlStatus;
1122 char buffer[ 128 + 8 ];
1127 sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_DBMS_NAME, buffer, 128 - 1,
1131 buffer[ bufLen ] =
'\0';
1132 if( bufLen >= 6 && !
strCompare( buffer,
"Access", 6 ) )
1134 if( bufLen >= 9 && !
strCompare( buffer,
"Interbase", 9 ) )
1136 if( bufLen >= 5 && !
strCompare( buffer,
"MySQL", 5 ) )
1138 if( bufLen >= 12 && !
strCompare( buffer,
"PostgreSQL", 10 ) )
1165 if( dbmsInfo->needsUpdate )
1167 SQLEndTran( SQL_HANDLE_DBC, dbmsInfo->hDbc, SQL_COMMIT );
1168 dbmsInfo->needsUpdate =
FALSE;
1174 if( dbmsInfo->hStmt[ i ] != NULL )
1176 SQLFreeHandle( SQL_HANDLE_STMT, dbmsInfo->hStmt[ i ] );
1177 dbmsInfo->hStmtPrepared[ i ] =
FALSE;
1178 dbmsInfo->hStmt[ i ] = NULL;
1181 SQLDisconnect( dbmsInfo->hDbc );
1182 SQLFreeHandle( SQL_HANDLE_DBC, dbmsInfo->hDbc );
1183 SQLFreeHandle( SQL_HANDLE_ENV, dbmsInfo->hEnv );
1184 dbmsInfo->hDbc = NULL;
1185 dbmsInfo->hEnv = NULL;
1210 ERROR_INFO *errorInfo = &dbmsInfo->errorInfo;
1213 SQLRETURN sqlStatus;
1218 assert(
isWritePtr( featureFlags,
sizeof(
int ) ) );
1230 if( hODBC == NULL_INSTANCE )
1235 status = dbmsParseName( &nameInfo, name, nameLen );
1245 sqlStatus = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE,
1257 "Couldn't allocate database connection handle", 44 );
1260 "Couldn't allocate database connection handle, this "
1261 "is probably due to an incorrect ODBC driver install "
1262 "or an invalid configuration", 130 );
1266 sqlStatus = SQLSetEnvAttr( dbmsInfo->hEnv, SQL_ATTR_ODBC_VERSION,
1270 sqlStatus = SQLAllocHandle( SQL_HANDLE_DBC, dbmsInfo->hEnv,
1276 SQLFreeHandle( SQL_HANDLE_ENV, dbmsInfo->hEnv );
1282 sqlStatus = SQLConnect( dbmsInfo->hDbc,
1283 nameInfo.name, ( SQLSMALLINT ) nameInfo.
nameLen,
1284 nameInfo.user, ( SQLSMALLINT ) nameInfo.
userLen,
1285 nameInfo.password, ( SQLSMALLINT ) nameInfo.
passwordLen );
1290 closeDatabase( dbmsInfo );
1295 for( i = 0; i < NO_CACHED_QUERIES &&
sqlStatusOK( sqlStatus ); i++ )
1296 sqlStatus = SQLAllocHandle( SQL_HANDLE_STMT, dbmsInfo->hDbc,
1297 &dbmsInfo->hStmt[ i ] );
1302 closeDatabase( dbmsInfo );
1310 ( void ) SQLSetStmtAttr( dbmsInfo->hDbc, SQL_ATTR_ACCESS_MODE,
1326 ( void ) SQLSetStmtAttr( dbmsInfo->hStmt[ i ], SQL_ATTR_CURSOR_TYPE,
1331 ( void ) SQLSetStmtAttr( dbmsInfo->hStmt[ i ],
1332 SQL_ATTR_CONCURRENCY,
1336 ( void ) SQLSetStmtAttr( dbmsInfo->hStmt[ i ], SQL_ATTR_NOSCAN,
1343 status = getDatatypeInfo( dbmsInfo, featureFlags );
1345 status = getBackendInfo( dbmsInfo );
1348 closeDatabase( dbmsInfo );
1364 static
int fetchData(
const SQLHSTMT hStmt,
1373 ERROR_INFO *errorInfo = &dbmsInfo->errorInfo;
1375 const SQLSMALLINT
dataType = ( SQLSMALLINT ) \
1376 ( ( dbmsInfo->hasBinaryBlobs ) ? \
1377 SQL_C_BINARY : SQL_C_CHAR );
1378 SQLRETURN sqlStatus;
1382 data == NULL && dataMaxLength == 0 && dataLength == NULL ) || \
1389 data == NULL && dataMaxLength == 0 && \
1390 dataLength == NULL ) || \
1392 data != NULL && dataMaxLength >= 16 && \
1394 dataLength != NULL ) );
1401 memset( data, 0,
min( 16, dataMaxLength ) );
1406 sqlStatus = SQLFetch( hStmt );
1413 if( sqlStatus == SQL_NO_DATA )
1434 sqlStatus = SQLGetData( hStmt, 1, dataType, data, dataMaxLength,
1439 *dataLength = ( int ) length;
1459 const SQLHSTMT hStmt = dbmsInfo->hStmt[ queryEntry ];
1460 BOUND_DATA_STATE boundDataState;
1461 SQLRETURN sqlStatus;
1465 assert( ( command == NULL && commandLength == 0 && \
1469 assert( ( data == NULL && dataMaxLength == 0 && dataLength == NULL ) || \
1472 assert( ( boundData == NULL ) || \
1478 command == NULL && commandLength == 0 ) || \
1482 command != NULL && \
1484 REQUIRES( ( data == NULL && dataMaxLength == 0 && \
1485 dataLength == NULL ) || \
1486 ( data != NULL && dataMaxLength >= 16 && \
1488 dataLength != NULL ) );
1495 if( dataLength != NULL )
1507 if( !dbmsInfo->hStmtPrepared[ queryEntry ] )
1513 &queryLength, command, commandLength );
1516 sqlStatus = SQLPrepare( hStmt, query, queryLength );
1521 dbmsInfo->hStmtPrepared[ queryEntry ] =
TRUE;
1525 if( boundData != NULL )
1527 status = bindParameters( hStmt, boundData, &boundDataState,
1538 sqlStatus = SQLExecute( hStmt );
1554 dataMaxLength >= 16 && \
1561 status = fetchData( dbmsInfo->hStmt[ queryEntry ], data,
1562 dataMaxLength, dataLength,
1571 SQLCloseCursor( dbmsInfo->hStmt[ queryEntry ] );
1580 ( void ) SQLSetStmtAttr( hStmt, SQL_ATTR_MAX_ROWS,
1584 sqlStatus = SQLExecute( hStmt );
1587 status = fetchData( hStmt, data, dataMaxLength, dataLength,
1588 queryType, dbmsInfo );
1589 SQLCloseCursor( hStmt );
1598 ( void ) SQLSetStmtAttr( hStmt, SQL_ATTR_MAX_ROWS,
1625 BOUND_DATA_STATE boundDataState;
1626 SQLRETURN sqlStatus;
1631 assert( ( command == NULL && commandLength == 0 && \
1634 assert( ( boundData == NULL ) || \
1639 command == NULL && commandLength == 0 ) || \
1641 command != NULL && \
1650 sqlStatus = SQLEndTran( SQL_HANDLE_DBC, dbmsInfo->hDbc,
1652 ( void ) SQLSetConnectAttr( dbmsInfo->hDbc, SQL_ATTR_AUTOCOMMIT,
1664 ( void ) SQLSetConnectAttr( dbmsInfo->hDbc, SQL_ATTR_AUTOCOMMIT,
1670 if( boundData != NULL )
1672 status = bindParameters( hStmt, boundData, &boundDataState,
1680 command, commandLength );
1683 sqlStatus = SQLExecDirect( hStmt, query, queryLength );
1695 if( sqlStatus == SQL_NO_DATA && \
1696 command != NULL && commandLength >= 6 && \
1719 if( command != NULL && commandLength >= 6 && \
1722 SQLINTEGER rowCount;
1724 sqlStatus = SQLRowCount( hStmt, &rowCount );
1737 sqlStatus = SQLEndTran( SQL_HANDLE_DBC, dbmsInfo->hDbc,
1740 SQL_ROLLBACK : SQL_COMMIT ) );
1741 if( dbmsInfo->transactIsDestructive )
1748 dbmsInfo->hStmtPrepared[ i ] =
FALSE;
1750 ( void ) SQLSetConnectAttr( dbmsInfo->hDbc, SQL_ATTR_AUTOCOMMIT,
1770 dbmsInfo->openDatabaseBackend = openDatabase;
1771 dbmsInfo->closeDatabaseBackend = closeDatabase;
1772 dbmsInfo->performUpdateBackend = performUpdate;
1773 dbmsInfo->performQueryBackend = performQuery;
1783 #define processCommand( stateInfo, buffer ) \
1784 odbcProcessCommand( stateInfo, buffer )