Procházet zdrojové kódy

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 před 12 roky
rodič
revize
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_exec_procedure: FStatementType := stExecProcedure;
     end;
+    FSelectable := FStatementType in [stSelect,stExecProcedure];
 
-    if FStatementType in [stSelect,stExecProcedure] then
+    if FSelectable then
       begin
       if isc_dsql_describe(@Status[0], @Statement, 1, SQLDA) <> 0 then
         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
     FParamReplaceString: string;
   protected
-    FCanOpen: boolean;                                // can return rows?
     FRowsAffected: integer;
     function ReplaceParams(AParams: TParams): string; // replaces parameters placeholders $1,$2,..$n in FQuery with supplied values in AParams
     procedure Prepare(Buf: string; AParams: TParams);
@@ -608,17 +607,17 @@ begin
 
   res := SUCCEED;
   repeat
-    c.FCanOpen := dbcmdrow(FDBProc)=SUCCEED;
+    c.FSelectable := dbcmdrow(FDBProc)=SUCCEED;
     c.FRowsAffected := dbcount(FDBProc);
     if assigned(dbiscount) and not dbiscount(FDBProc) then
       c.FRowsAffected := -1;
 
-    if not c.FCanOpen then  //Sybase stored proc.
+    if not c.FSelectable then  //Sybase stored proc.
     begin
       repeat until dbnextrow(FDBProc) = NO_MORE_ROWS;
       res := CheckError( dbresults(FDBProc) );
     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
     Fstatus := NO_MORE_ROWS

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

@@ -59,7 +59,6 @@ Type
   TCursorName = Class(TSQLCursor)
   protected
     FRes: PMYSQL_RES;                   { Record pointer }
-    FNeedData : Boolean;
     FStatement : String;
     Row : MYSQL_ROW;
     Lengths : pculong;                  { Lengths of the columns of the current row }
@@ -515,8 +514,6 @@ begin
     FStatement:=Buf;
     if assigned(AParams) and (AParams.count > 0) then
       FStatement := AParams.ParseSQL(FStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
-    if FStatementType in [stSelect,stExecProcedure] then
-      FNeedData:=True;
     end
 end;
 
@@ -540,8 +537,6 @@ Var
 
 begin
   C:=Cursor as TCursorName;
-  if c.FStatementType in [stSelect,stExecProcedure] then
-    c.FNeedData:=False;
   if assigned(C.FRes) then
     begin
     mysql_free_result(C.FRes);
@@ -582,15 +577,18 @@ begin
       begin
       C.RowsAffected := mysql_affected_rows(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
           begin
           mysql_free_result(C.FRes);
           C.FRes:=Res;
+          C.FSelectable:=True;
           end;
-        until mysql_next_result(FMySQL)<>0;
+      until mysql_next_result(FMySQL)<>0;
       end;
     end;
 end;

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

@@ -747,6 +747,7 @@ const
 var
   ODBCCursor:TODBCCursor;
   Res:SQLRETURN;
+  ColumnCount:SQLSMALLINT;
 begin
   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 ODBCSucces(SQLNumResultCols(ODBCCursor.FSTMTHandle, ColumnCount)) then
+      ODBCCursor.FSelectable:=ColumnCount>0
+    else
+      ODBCCursor.FSelectable:=False;
+
   finally
     // free parameter buffers
     FreeParamBuffers(ODBCCursor);

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

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

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

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

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

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