Browse Source

fcl-db: introduce FSelectable as new TSQLCursor class field. Update sql connectors to set it after Preparation or Execution of sql statement to signal if there will be or is result set. This change is neutral. In next commit I will use FSelectable to determine if allow Open or raise SErrNoSelectStatement.
(motivation is that there are many various statements, that are not stSelect nor stExecProcedure, which also return result set)

git-svn-id: trunk@23136 -

lacak 12 years ago
parent
commit
6a9c3a6061

+ 2 - 1
packages/fcl-db/src/sqldb/interbase/ibconnection.pp

@@ -742,8 +742,9 @@ begin
       isc_info_sql_stmt_delete: FStatementType := stDelete;
       isc_info_sql_stmt_delete: FStatementType := stDelete;
       isc_info_sql_stmt_exec_procedure: FStatementType := stExecProcedure;
       isc_info_sql_stmt_exec_procedure: FStatementType := stExecProcedure;
     end;
     end;
+    FSelectable := FStatementType in [stSelect,stExecProcedure];
 
 
-    if FStatementType in [stSelect,stExecProcedure] then
+    if FSelectable then
       begin
       begin
       if isc_dsql_describe(@Status[0], @Statement, 1, SQLDA) <> 0 then
       if isc_dsql_describe(@Status[0], @Statement, 1, SQLDA) <> 0 then
         CheckError('PrepareSelect', Status);
         CheckError('PrepareSelect', Status);

+ 3 - 4
packages/fcl-db/src/sqldb/mssql/mssqlconn.pp

@@ -178,7 +178,6 @@ type
     FQuery: string;                                   // :ParamNames converted to $1,$2,..,$n
     FQuery: string;                                   // :ParamNames converted to $1,$2,..,$n
     FParamReplaceString: string;
     FParamReplaceString: string;
   protected
   protected
-    FCanOpen: boolean;                                // can return rows?
     FRowsAffected: integer;
     FRowsAffected: integer;
     function ReplaceParams(AParams: TParams): string; // replaces parameters placeholders $1,$2,..$n in FQuery with supplied values in AParams
     function ReplaceParams(AParams: TParams): string; // replaces parameters placeholders $1,$2,..$n in FQuery with supplied values in AParams
     procedure Prepare(Buf: string; AParams: TParams);
     procedure Prepare(Buf: string; AParams: TParams);
@@ -608,17 +607,17 @@ begin
 
 
   res := SUCCEED;
   res := SUCCEED;
   repeat
   repeat
-    c.FCanOpen := dbcmdrow(FDBProc)=SUCCEED;
+    c.FSelectable := dbcmdrow(FDBProc)=SUCCEED;
     c.FRowsAffected := dbcount(FDBProc);
     c.FRowsAffected := dbcount(FDBProc);
     if assigned(dbiscount) and not dbiscount(FDBProc) then
     if assigned(dbiscount) and not dbiscount(FDBProc) then
       c.FRowsAffected := -1;
       c.FRowsAffected := -1;
 
 
-    if not c.FCanOpen then  //Sybase stored proc.
+    if not c.FSelectable then  //Sybase stored proc.
     begin
     begin
       repeat until dbnextrow(FDBProc) = NO_MORE_ROWS;
       repeat until dbnextrow(FDBProc) = NO_MORE_ROWS;
       res := CheckError( dbresults(FDBProc) );
       res := CheckError( dbresults(FDBProc) );
     end;
     end;
-  until c.FCanOpen or (res = NO_MORE_RESULTS) or (res = FAIL);
+  until c.FSelectable or (res = NO_MORE_RESULTS) or (res = FAIL);
 
 
   if res = NO_MORE_RESULTS then
   if res = NO_MORE_RESULTS then
     Fstatus := NO_MORE_ROWS
     Fstatus := NO_MORE_ROWS

+ 7 - 9
packages/fcl-db/src/sqldb/mysql/mysqlconn.inc

@@ -59,7 +59,6 @@ Type
   TCursorName = Class(TSQLCursor)
   TCursorName = Class(TSQLCursor)
   protected
   protected
     FRes: PMYSQL_RES;                   { Record pointer }
     FRes: PMYSQL_RES;                   { Record pointer }
-    FNeedData : Boolean;
     FStatement : String;
     FStatement : String;
     Row : MYSQL_ROW;
     Row : MYSQL_ROW;
     Lengths : pculong;                  { Lengths of the columns of the current row }
     Lengths : pculong;                  { Lengths of the columns of the current row }
@@ -515,8 +514,6 @@ begin
     FStatement:=Buf;
     FStatement:=Buf;
     if assigned(AParams) and (AParams.count > 0) then
     if assigned(AParams) and (AParams.count > 0) then
       FStatement := AParams.ParseSQL(FStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
       FStatement := AParams.ParseSQL(FStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
-    if FStatementType in [stSelect,stExecProcedure] then
-      FNeedData:=True;
     end
     end
 end;
 end;
 
 
@@ -540,8 +537,6 @@ Var
 
 
 begin
 begin
   C:=Cursor as TCursorName;
   C:=Cursor as TCursorName;
-  if c.FStatementType in [stSelect,stExecProcedure] then
-    c.FNeedData:=False;
   if assigned(C.FRes) then
   if assigned(C.FRes) then
     begin
     begin
     mysql_free_result(C.FRes);
     mysql_free_result(C.FRes);
@@ -582,15 +577,18 @@ begin
       begin
       begin
       C.RowsAffected := mysql_affected_rows(FMYSQL);
       C.RowsAffected := mysql_affected_rows(FMYSQL);
       C.LastInsertID := mysql_insert_id(FMYSQL);
       C.LastInsertID := mysql_insert_id(FMYSQL);
-      if C.FNeedData then
-        repeat
-        Res:=mysql_store_result(FMySQL); //returns a null pointer if the statement didn't return a result set
+      C.FSelectable  := False;
+      repeat
+        Res:=mysql_store_result(FMySQL); //returns a null pointer also if the statement didn't return a result set
+        if mysql_errno(FMySQL)<>0 then
+          MySQLError(FMySQL, SErrGettingResult, Self);
         if Res<>nil then
         if Res<>nil then
           begin
           begin
           mysql_free_result(C.FRes);
           mysql_free_result(C.FRes);
           C.FRes:=Res;
           C.FRes:=Res;
+          C.FSelectable:=True;
           end;
           end;
-        until mysql_next_result(FMySQL)<>0;
+      until mysql_next_result(FMySQL)<>0;
       end;
       end;
     end;
     end;
 end;
 end;

+ 6 - 0
packages/fcl-db/src/sqldb/odbc/odbcconn.pas

@@ -747,6 +747,7 @@ const
 var
 var
   ODBCCursor:TODBCCursor;
   ODBCCursor:TODBCCursor;
   Res:SQLRETURN;
   Res:SQLRETURN;
+  ColumnCount:SQLSMALLINT;
 begin
 begin
   ODBCCursor:=cursor as TODBCCursor;
   ODBCCursor:=cursor as TODBCCursor;
 
 
@@ -765,6 +766,11 @@ begin
 
 
     if (Res<>SQL_NO_DATA) then ODBCCheckResult( Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not execute statement.' );
     if (Res<>SQL_NO_DATA) then ODBCCheckResult( Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not execute statement.' );
 
 
+    if ODBCSucces(SQLNumResultCols(ODBCCursor.FSTMTHandle, ColumnCount)) then
+      ODBCCursor.FSelectable:=ColumnCount>0
+    else
+      ODBCCursor.FSelectable:=False;
+
   finally
   finally
     // free parameter buffers
     // free parameter buffers
     FreeParamBuffers(ODBCCursor);
     FreeParamBuffers(ODBCCursor);

+ 1 - 0
packages/fcl-db/src/sqldb/postgres/pqconnection.pp

@@ -711,6 +711,7 @@ begin
 //      atransaction.Rollback;
 //      atransaction.Rollback;
       raise E;
       raise E;
       end;
       end;
+    FSelectable := assigned(res) and (PQresultStatus(res)=PGRES_TUPLES_OK);
     end;
     end;
 end;
 end;
 
 

+ 3 - 0
packages/fcl-db/src/sqldb/sqldb.pp

@@ -53,6 +53,7 @@ type
   TSQLCursor = Class(TSQLHandle)
   TSQLCursor = Class(TSQLHandle)
   public
   public
     FPrepared      : Boolean;
     FPrepared      : Boolean;
+    FSelectable    : Boolean;
     FInitFieldDef  : Boolean;
     FInitFieldDef  : Boolean;
     FStatementType : TStatementType;
     FStatementType : TStatementType;
     FSchemaType    : TSchemaType;
     FSchemaType    : TSchemaType;
@@ -1124,6 +1125,7 @@ begin
     // unpredictable results.
     // unpredictable results.
     if not assigned(fcursor) then
     if not assigned(fcursor) then
       FCursor := Db.AllocateCursorHandle;
       FCursor := Db.AllocateCursorHandle;
+    FCursor.FSelectable:=True; // let PrepareStatement and/or Execute alter it
     FCursor.FStatementType:=StmType;
     FCursor.FStatementType:=StmType;
     FCursor.FSchemaType := FSchemaType;
     FCursor.FSchemaType := FSchemaType;
     if ServerFiltered then
     if ServerFiltered then
@@ -1422,6 +1424,7 @@ begin
     begin
     begin
     if not assigned(fcursor) then
     if not assigned(fcursor) then
       FCursor := TSQLConnection(Database).AllocateCursorHandle;
       FCursor := TSQLConnection(Database).AllocateCursorHandle;
+    FCursor.FSelectable:=True;
     FCursor.FStatementType:=stSelect;
     FCursor.FStatementType:=stSelect;
     FUpdateable:=True;
     FUpdateable:=True;
     end
     end

+ 2 - 1
packages/fcl-db/src/sqldb/sqlite/sqlite3conn.pp

@@ -273,8 +273,9 @@ begin
 {$endif}
 {$endif}
   if (fstate<=sqliteerrormax) then
   if (fstate<=sqliteerrormax) then
     checkerror(sqlite3_reset(fstatement));
     checkerror(sqlite3_reset(fstatement));
+  FSelectable :=sqlite3_column_count(fstatement)>0;
   RowsAffected:=sqlite3_changes(fhandle);
   RowsAffected:=sqlite3_changes(fhandle);
-  if (fstate=sqlite_row) then 
+  if (fstate=sqlite_row) then
     fstate:= sqliteerrormax; //first row
     fstate:= sqliteerrormax; //first row
 end;  
 end;