Browse Source

+ Patch from Bram Kuijvenhoven:
- pass ODBC api call return values to ODBCCheckResult function explicitly
instead of using SQLGetDiagRec (improves error reporting with unixODBC)
- fixed TODBCConnection.Param property; no semicolons were inserted to separate
the parameters in the connection string

git-svn-id: trunk@1677 -

joost 20 years ago
parent
commit
f41ff8ac78
1 changed files with 127 additions and 91 deletions
  1. 127 91
      fcl/db/sqldb/odbc/odbcconn.pas

+ 127 - 91
fcl/db/sqldb/odbc/odbcconn.pas

@@ -154,7 +154,7 @@ begin
   end;
 end;
 
-procedure ODBCCheckResult(HandleType:SQLSMALLINT; AHandle: SQLHANDLE; ErrorMsg: string);
+procedure ODBCCheckResult(LastReturnCode:SQLRETURN; HandleType:SQLSMALLINT; AHandle: SQLHANDLE; ErrorMsg: string);
 
   // check return value from SQLGetDiagField/Rec function itself
   procedure CheckSQLGetDiagResult(const Res:SQLRETURN);
@@ -172,13 +172,11 @@ procedure ODBCCheckResult(HandleType:SQLSMALLINT; AHandle: SQLHANDLE; ErrorMsg:
 var
   NativeError:SQLINTEGER;
   TextLength:SQLSMALLINT;
-  Res,LastReturnCode:SQLRETURN;
+  Res:SQLRETURN;
   SqlState,MessageText,TotalMessage:string;
   RecNumber:SQLSMALLINT;
 begin
   // check result
-  Res:=SQLGetDiagField(HandleType,AHandle,0,SQL_DIAG_RETURNCODE,@LastReturnCode,SQL_IS_SMALLINT,TextLength);
-  CheckSQLGetDiagResult(Res);
   if ODBCSucces(LastReturnCode) then
     Exit; // no error; all is ok
 
@@ -253,7 +251,7 @@ begin
     else if EqualSignPos=1 then
       raise EODBCException.CreateFmt('Invalid parameter in Params[%d]; no identifier before the ''='' in ''%s''',[i, Param])
     else
-      Result:=Result + EscapeParamValue(Copy(Param,1,EqualSignPos-1))+'='+EscapeParamValue(Copy(Param,EqualSignPos+1,MaxInt));
+      Result:=Result + EscapeParamValue(Copy(Param,1,EqualSignPos-1))+'='+EscapeParamValue(Copy(Param,EqualSignPos+1,MaxInt))+';';
   end;
 end;
 
@@ -286,17 +284,19 @@ begin
           IntVal:=AParams[ParamIndex].AsInteger;
           Move(IntVal,Buf^,4);
           ODBCCursor.FParamBuf[i]:=Buf;
-          SQLBindParameter(ODBCCursor.FSTMTHandle, // StatementHandle
-                           i+1,                    // ParameterNumber
-                           SQL_PARAM_INPUT,        // InputOutputType
-                           SQL_C_LONG,             // ValueType
-                           SQL_INTEGER,            // ParameterType
-                           10,                     // ColumnSize
-                           0,                      // DecimalDigits
-                           Buf,                    // ParameterValuePtr
-                           0,                      // BufferLength
-                           nil);                   // StrLen_or_IndPtr
-          ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not bind parameter %d',[i]));
+          ODBCCheckResult(
+            SQLBindParameter(ODBCCursor.FSTMTHandle, // StatementHandle
+                             i+1,                    // ParameterNumber
+                             SQL_PARAM_INPUT,        // InputOutputType
+                             SQL_C_LONG,             // ValueType
+                             SQL_INTEGER,            // ParameterType
+                             10,                     // ColumnSize
+                             0,                      // DecimalDigits
+                             Buf,                    // ParameterValuePtr
+                             0,                      // BufferLength
+                             nil),                   // StrLen_or_IndPtr
+            SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not bind parameter %d',[i])
+          );
         end;
       ftString:
         begin
@@ -306,17 +306,19 @@ begin
           Move(StrLen,    buf^,                    SizeOf(SQLINTEGER));
           Move(StrVal[1],(buf+SizeOf(SQLINTEGER))^,StrLen);
           ODBCCursor.FParamBuf[i]:=Buf;
-          SQLBindParameter(ODBCCursor.FSTMTHandle, // StatementHandle
-                           i+1,                    // ParameterNumber
-                           SQL_PARAM_INPUT,        // InputOutputType
-                           SQL_C_CHAR,             // ValueType
-                           SQL_CHAR,               // ParameterType
-                           StrLen,                 // ColumnSize
-                           0,                      // DecimalDigits
-                           buf+SizeOf(SQLINTEGER), // ParameterValuePtr
-                           StrLen,                 // BufferLength
-                           Buf);                   // StrLen_or_IndPtr
-          ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not bind parameter %d',[i]));
+          ODBCCheckResult(
+            SQLBindParameter(ODBCCursor.FSTMTHandle, // StatementHandle
+                             i+1,                    // ParameterNumber
+                             SQL_PARAM_INPUT,        // InputOutputType
+                             SQL_C_CHAR,             // ValueType
+                             SQL_CHAR,               // ParameterType
+                             StrLen,                 // ColumnSize
+                             0,                      // DecimalDigits
+                             buf+SizeOf(SQLINTEGER), // ParameterValuePtr
+                             StrLen,                 // BufferLength
+                             Buf),                   // StrLen_or_IndPtr
+            SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not bind parameter %d',[i])
+          );
         end;
     else
       raise EDataBaseError.CreateFmt('Parameter %d is of type %s, which not supported yet',[ParamIndex, Fieldtypenames[AParams[ParamIndex].DataType]]);
@@ -359,38 +361,49 @@ begin
   end;
 
   // allocate connection handle
-  SQLAllocHandle(SQL_HANDLE_DBC,Environment.FENVHandle,FDBCHandle);
-  ODBCCheckResult(SQL_HANDLE_ENV,Environment.FENVHandle,'Could not allocate ODBC Connection handle.');
+  ODBCCheckResult(
+    SQLAllocHandle(SQL_HANDLE_DBC,Environment.FENVHandle,FDBCHandle),
+    SQL_HANDLE_ENV,Environment.FENVHandle,'Could not allocate ODBC Connection handle.'
+  );
 
   // connect
   ConnectionString:=CreateConnectionString;
   SetLength(OutConnectionString,BufferLength-1); // allocate completed connection string buffer (using the ansistring #0 trick)
-  SQLDriverConnect(FDBCHandle,               // the ODBC connection handle
-                   nil,                      // no parent window (would be required for prompts)
-                   PChar(ConnectionString),  // the connection string
-                   Length(ConnectionString), // connection string length
-                   @(OutConnectionString[1]),// buffer for storing the completed connection string
-                   BufferLength,             // length of the buffer
-                   ActualLength,             // the actual length of the completed connection string
-                   SQL_DRIVER_NOPROMPT);     // don't prompt for password etc.
-  ODBCCheckResult(SQL_HANDLE_DBC,FDBCHandle,Format('Could not connect with connection string "%s".',[ConnectionString]));
-  if ActualLength<BufferLength-1 then
-    SetLength(OutConnectionString,ActualLength); // fix completed connection string length
+  ODBCCheckResult(
+    SQLDriverConnect(FDBCHandle,               // the ODBC connection handle
+                     nil,                      // no parent window (would be required for prompts)
+                     PChar(ConnectionString),  // the connection string
+                     Length(ConnectionString), // connection string length
+                     @(OutConnectionString[1]),// buffer for storing the completed connection string
+                     BufferLength,             // length of the buffer
+                     ActualLength,             // the actual length of the completed connection string
+                     SQL_DRIVER_NOPROMPT),     // don't prompt for password etc.
+    SQL_HANDLE_DBC,FDBCHandle,Format('Could not connect with connection string "%s".',[ConnectionString])
+  );
+
+// commented out as the OutConenctionString is not used further at the moment
+//  if ActualLength<BufferLength-1 then
+//    SetLength(OutConnectionString,ActualLength); // fix completed connection string length
 
   // set connection attributes (none yet)
 end;
 
 procedure TODBCConnection.DoInternalDisconnect;
+var
+  Res:SQLRETURN;
 begin
   inherited DoInternalDisconnect;
 
   // disconnect
-  SQLDisconnect(FDBCHandle);
-  ODBCCheckResult(SQL_HANDLE_DBC,FDBCHandle,'Could not disconnect.');
+  ODBCCheckResult(
+    SQLDisconnect(FDBCHandle),
+    SQL_HANDLE_DBC,FDBCHandle,'Could not disconnect.'
+  );
 
   // deallocate connection handle
-  if SQLFreeHandle(SQL_HANDLE_DBC, FDBCHandle)=SQL_ERROR then
-    ODBCCheckResult(SQL_HANDLE_DBC,FDBCHandle,'Could not free connection handle.');
+  Res:=SQLFreeHandle(SQL_HANDLE_DBC, FDBCHandle);
+  if Res=SQL_ERROR then
+    ODBCCheckResult(Res,SQL_HANDLE_DBC,FDBCHandle,'Could not free connection handle.');
 end;
 
 function TODBCConnection.AllocateCursorHandle: TSQLCursor;
@@ -427,8 +440,10 @@ begin
     buf := AParams.ParseSQL(buf,false,psInterbase,ODBCCursor.FParamIndex);
 
   // prepare statement
-  SQLPrepare(ODBCCursor.FSTMTHandle, PChar(Buf), Length(Buf));
-  ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not prepare statement.');
+  ODBCCheckResult(
+    SQLPrepare(ODBCCursor.FSTMTHandle, PChar(buf), Length(buf)),
+    SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not prepare statement.'
+  );
 
   ODBCCursor.FQuery:=Buf;
 end;
@@ -478,8 +493,10 @@ begin
   SetParameters(ODBCCursor, AParams);
 
   // execute the statement
-  SQLExecute(ODBCCursor.FSTMTHandle);
-  ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not execute statement.');
+  ODBCCheckResult(
+    SQLExecute(ODBCCursor.FSTMTHandle),
+    SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not execute statement.'
+  );
 
   // free parameter buffers
   FreeParamBuffers(ODBCCursor);
@@ -495,7 +512,7 @@ begin
   // fetch new row
   Res:=SQLFetch(ODBCCursor.FSTMTHandle);
   if Res<>SQL_NO_DATA then
-    ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not fetch new row from result set');
+    ODBCCheckResult(Res,SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not fetch new row from result set');
 
   // result is true iff a new row was available
   Result:=Res<>SQL_NO_DATA;
@@ -509,6 +526,7 @@ var
   ODBCTimeStruct:SQL_TIME_STRUCT;
   ODBCTimeStampStruct:SQL_TIMESTAMP_STRUCT;
   DateTime:TDateTime;
+  Res:SQLRETURN;
 begin
   ODBCCursor:=cursor as TODBCCursor;
 
@@ -517,44 +535,44 @@ begin
   // TODO: finish this
   case FieldDef.DataType of
     ftFixedChar,ftString: // are both mapped to TStringField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_CHAR, buffer, FieldDef.Size, @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_CHAR, buffer, FieldDef.Size, @StrLenOrInd);
     ftSmallint:           // mapped to TSmallintField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SSHORT, buffer, SizeOf(Smallint), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SSHORT, buffer, SizeOf(Smallint), @StrLenOrInd);
     ftInteger,ftWord:     // mapped to TLongintField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SLONG, buffer, SizeOf(Longint), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SLONG, buffer, SizeOf(Longint), @StrLenOrInd);
     ftLargeint:           // mapped to TLargeintField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SBIGINT, buffer, SizeOf(Largeint), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SBIGINT, buffer, SizeOf(Largeint), @StrLenOrInd);
     ftFloat:              // mapped to TFloatField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_DOUBLE, buffer, SizeOf(Double), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_DOUBLE, buffer, SizeOf(Double), @StrLenOrInd);
     ftTime:               // mapped to TTimeField
     begin
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIME, @ODBCTimeStruct, SizeOf(SQL_TIME_STRUCT), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIME, @ODBCTimeStruct, SizeOf(SQL_TIME_STRUCT), @StrLenOrInd);
       DateTime:=TimeStructToDateTime(@ODBCTimeStruct);
       Move(DateTime, buffer^, SizeOf(TDateTime));
     end;
     ftDate:               // mapped to TDateField
     begin
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_DATE, @ODBCDateStruct, SizeOf(SQL_DATE_STRUCT), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_DATE, @ODBCDateStruct, SizeOf(SQL_DATE_STRUCT), @StrLenOrInd);
       DateTime:=DateStructToDateTime(@ODBCDateStruct);
       Move(DateTime, buffer^, SizeOf(TDateTime));
     end;
     ftDateTime:           // mapped to TDateTimeField
     begin
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIMESTAMP, @ODBCTimeStampStruct, SizeOf(SQL_TIMESTAMP_STRUCT), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIMESTAMP, @ODBCTimeStampStruct, SizeOf(SQL_TIMESTAMP_STRUCT), @StrLenOrInd);
       DateTime:=TimeStampStructToDateTime(@ODBCTimeStampStruct);
       Move(DateTime, buffer^, SizeOf(TDateTime));
     end;
     ftBoolean:            // mapped to TBooleanField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BIT, buffer, SizeOf(Wordbool), @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BIT, buffer, SizeOf(Wordbool), @StrLenOrInd);
     ftBytes:              // mapped to TBytesField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, FieldDef.Size, @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, FieldDef.Size, @StrLenOrInd);
     ftVarBytes:           // mapped to TVarBytesField
-      SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, FieldDef.Size, @StrLenOrInd);
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, FieldDef.Size, @StrLenOrInd);
     // TODO: Loading of other field types
   else
     raise EODBCException.CreateFmt('Tried to load field of unsupported field type %s',[Fieldtypenames[FieldDef.DataType]]);
   end;
-  ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not get field data for field ''%s'' (index %d).',[FieldDef.Name, FieldDef.Index+1]));
+  ODBCCheckResult(Res,SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not get field data for field ''%s'' (index %d).',[FieldDef.Name, FieldDef.Index+1]));
   Result:=StrLenOrInd<>SQL_NULL_DATA; // Result indicates whether the value is non-null
 
 //  writeln(Format('Field.Size: %d; StrLenOrInd: %d',[FieldDef.Size, StrLenOrInd]));
@@ -572,8 +590,10 @@ var
 begin
   ODBCCursor:=cursor as TODBCCursor;
 
-  SQLFreeStmt(ODBCCursor.FSTMTHandle, SQL_CLOSE);
-  ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not close ODBC statement cursor.');
+  ODBCCheckResult(
+    SQLFreeStmt(ODBCCursor.FSTMTHandle, SQL_CLOSE),
+    SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not close ODBC statement cursor.'
+  );
 end;
 
 procedure TODBCConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
@@ -592,24 +612,28 @@ begin
   ODBCCursor:=cursor as TODBCCursor;
 
   // get number of columns in result set
-  SQLNumResultCols(ODBCCursor.FSTMTHandle, ColumnCount);
-  ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not determine number of columns in result set.');
+  ODBCCheckResult(
+    SQLNumResultCols(ODBCCursor.FSTMTHandle, ColumnCount),
+    SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not determine number of columns in result set.'
+  );
 
   for i:=1 to ColumnCount do
   begin
     SetLength(ColName,ColNameDefaultLength); // also garantuees uniqueness
 
     // call with default column name buffer
-    SQLDescribeCol(ODBCCursor.FSTMTHandle, // statement handle
-                   i,                      // column number, is 1-based (Note: column 0 is the bookmark column in ODBC)
-                   @(ColName[1]),          // default buffer
-                   ColNameDefaultLength+1, // and its length; we include the #0 terminating any ansistring of Length > 0 in the buffer
-                   ColNameLength,          // actual column name length
-                   DataType,               // the SQL datatype for the column
-                   ColumnSize,             // column size
-                   DecimalDigits,          // number of decimal digits
-                   Nullable);              // SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
-    ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not get column properties for column %d.',[i]));
+    ODBCCheckResult(
+      SQLDescribeCol(ODBCCursor.FSTMTHandle, // statement handle
+                     i,                      // column number, is 1-based (Note: column 0 is the bookmark column in ODBC)
+                     @(ColName[1]),          // default buffer
+                     ColNameDefaultLength+1, // and its length; we include the #0 terminating any ansistring of Length > 0 in the buffer
+                     ColNameLength,          // actual column name length
+                     DataType,               // the SQL datatype for the column
+                     ColumnSize,             // column size
+                     DecimalDigits,          // number of decimal digits
+                     Nullable),              // SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
+      SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not get column properties for column %d.',[i])
+    );
 
     // truncate buffer or make buffer long enough for entire column name (note: the call is the same for both cases!)
     SetLength(ColName,ColNameLength);
@@ -617,14 +641,16 @@ begin
     if ColNameLength>ColNameDefaultLength then
     begin
       // request column name with buffer that is long enough
-      SQLColAttribute(ODBCCursor.FSTMTHandle, // statement handle
-                      i,                      // column number
-                      SQL_DESC_NAME,          // the column name or alias
-                      @(ColName[1]),          // buffer
-                      ColNameLength+1,        // buffer size
-                      @ColNameLength,         // actual length
-                      nil);                   // no numerical output
-      ODBCCheckResult(SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not get column name for column %d.',[i]));
+      ODBCCheckResult(
+        SQLColAttribute(ODBCCursor.FSTMTHandle, // statement handle
+                        i,                      // column number
+                        SQL_DESC_NAME,          // the column name or alias
+                        @(ColName[1]),          // buffer
+                        ColNameLength+1,        // buffer size
+                        @ColNameLength,         // actual length
+                        nil),                   // no numerical output
+        SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, Format('Could not get column name for column %d.',[i])
+      );
     end;
 
     // convert type
@@ -702,15 +728,20 @@ begin
     raise EODBCException.Create('Could not allocate ODBC Environment handle'); // we can't retrieve any more information, because we don't have a handle for the SQLGetDiag* functions
 
   // set odbc version
-  SQLSetEnvAttr(FENVHandle, SQL_ATTR_ODBC_VERSION, SQLPOINTER(SQL_OV_ODBC3), 0);
-  ODBCCheckResult(SQL_HANDLE_ENV, FENVHandle,'Could not set ODBC version to 3.');
+  ODBCCheckResult(
+    SQLSetEnvAttr(FENVHandle, SQL_ATTR_ODBC_VERSION, SQLPOINTER(SQL_OV_ODBC3), 0),
+    SQL_HANDLE_ENV, FENVHandle,'Could not set ODBC version to 3.'
+  );
 end;
 
 destructor TODBCEnvironment.Destroy;
+var
+  Res:SQLRETURN;
 begin
   // free environment handle
-  if SQLFreeHandle(SQL_HANDLE_ENV, FENVHandle)=SQL_ERROR then
-    ODBCCheckResult(SQL_HANDLE_ENV, FENVHandle, 'Could not free ODBC Environment handle.');
+  Res:=SQLFreeHandle(SQL_HANDLE_ENV, FENVHandle);
+  if Res=SQL_ERROR then
+    ODBCCheckResult(Res,SQL_HANDLE_ENV, FENVHandle, 'Could not free ODBC Environment handle.');
 
   // free odbc if not used by any TODBCEnvironment object anymore
   Dec(ODBCLoadCount);
@@ -722,19 +753,24 @@ end;
 constructor TODBCCursor.Create(Connection:TODBCConnection);
 begin
   // allocate statement handle
-  SQLAllocHandle(SQL_HANDLE_STMT, Connection.FDBCHandle, FSTMTHandle);
-  ODBCCheckResult(SQL_HANDLE_DBC, Connection.FDBCHandle, 'Could not allocate ODBC Statement handle.');
+  ODBCCheckResult(
+    SQLAllocHandle(SQL_HANDLE_STMT, Connection.FDBCHandle, FSTMTHandle),
+    SQL_HANDLE_DBC, Connection.FDBCHandle, 'Could not allocate ODBC Statement handle.'
+  );
 end;
 
 destructor TODBCCursor.Destroy;
+var
+  Res:SQLRETURN;
 begin
   inherited Destroy;
 
   if FSTMTHandle<>SQL_INVALID_HANDLE then
   begin
     // deallocate statement handle
-    if SQLFreeHandle(SQL_HANDLE_STMT, FSTMTHandle)=SQL_ERROR then
-      ODBCCheckResult(SQL_HANDLE_STMT, FSTMTHandle, 'Could not free ODBC Statement handle.');
+    Res:=SQLFreeHandle(SQL_HANDLE_STMT, FSTMTHandle);
+    if Res=SQL_ERROR then
+      ODBCCheckResult(Res,SQL_HANDLE_STMT, FSTMTHandle, 'Could not free ODBC Statement handle.');
   end;
 end;