]> granicus.if.org Git - postgresql/commitdiff
Update 06-40-0004 -- Add Bookmark support!
authorByron Nikolaidis <byronn@insightdist.com>
Fri, 8 Jan 1999 18:24:45 +0000 (18:24 +0000)
committerByron Nikolaidis <byronn@insightdist.com>
Fri, 8 Jan 1999 18:24:45 +0000 (18:24 +0000)
src/interfaces/odbc/bind.c
src/interfaces/odbc/environ.c
src/interfaces/odbc/info.c
src/interfaces/odbc/options.c
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/psqlodbc.rc
src/interfaces/odbc/results.c
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.h

index 512f352181aa3c51699b58f4392c016addba15f5..285fabd75abeeb11109487374acd7c0456f9b005 100644 (file)
@@ -162,13 +162,6 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
                return SQL_INVALID_HANDLE;
        }
 
-       if (icol < 1) {
-               /* currently we do not support bookmarks */
-               stmt->errormsg = "Bookmarks are not currently supported.";
-               stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
-       }
 
        SC_clear_error(stmt);
     
@@ -179,6 +172,28 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
                return SQL_ERROR;
        }
 
+       /*      If the bookmark column is being bound, then just save it */
+       if (icol == 0) {
+
+               if (rgbValue == NULL) {
+                       stmt->bookmark.buffer = NULL;
+                       stmt->bookmark.used = NULL;
+               }
+               else {
+                       /*      Make sure it is the bookmark data type */
+                       if ( fCType != SQL_C_BOOKMARK) {
+                               stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK";
+                               stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE;
+                               SC_log_error(func, "", stmt);
+                               return SQL_ERROR;
+                       }
+
+                       stmt->bookmark.buffer = rgbValue;
+                       stmt->bookmark.used = pcbValue;
+               }
+               return SQL_SUCCESS;
+       }
+
        //      allocate enough bindings if not already done
        //      Most likely, execution of a statement would have setup the 
        //      necessary bindings. But some apps call BindCol before any
index 1fa005b4c46f4e2e4e6df400138f573d5fc8c372..3190adfd8b5c89d22fa1598beb2d647f8d594819 100644 (file)
@@ -190,6 +190,11 @@ int status;
                                case STMT_VALUE_OUT_OF_RANGE:
                                        strcpy(szSqlState, "22003");
                                        break;
+
+                               case STMT_OPERATION_INVALID:
+                                       strcpy(szSqlState, "S1011");
+                                       break;
+
                                default:
                     strcpy(szSqlState, "S1000");
                     // also a general error
index 9a001264e6252a53ad53ca6a309a660df2e2a5db..9e019dbba3c4d6f1942a92da50a2e79e85062756 100644 (file)
@@ -107,8 +107,9 @@ RETCODE result;
         break;
 
     case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
-        len = 4;
-        value = 0;
+               /* very simple bookmark support */        
+               len = 4;
+        value = globals.use_declarefetch ? 0 : (SQL_BP_SCROLL);                
         break;
 
     case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
@@ -221,7 +222,8 @@ RETCODE result;
                                    SQL_FD_FETCH_LAST |
                                    SQL_FD_FETCH_PRIOR |
                                    SQL_FD_FETCH_ABSOLUTE |
-                                                                  SQL_FD_FETCH_RELATIVE);
+                                                                  SQL_FD_FETCH_RELATIVE | 
+                                                                  SQL_FD_FETCH_BOOKMARK);
         break;
 
     case SQL_FILE_USAGE: /* ODBC 2.0 */
index 6621acadf54a135502363ce42e695c0f55ffd7ab..f16ec4bc4a5219df5335888753217aaed548bbfd 100644 (file)
@@ -32,6 +32,7 @@
 #include "environ.h"
 #include "connection.h"
 #include "statement.h"
+#include "qresult.h"
 
 
 extern GLOBAL_VALUES globals;
@@ -189,7 +190,6 @@ char changed = FALSE;
                if (conn) conn->stmtOptions.rowset_size = vParam;
                if (stmt) stmt->options.rowset_size = vParam;
 
-
                break;
 
        case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
@@ -205,18 +205,11 @@ char changed = FALSE;
                }
                return SQL_ERROR;
 
-       case SQL_USE_BOOKMARKS: /* NOT SUPPORTED */
-               if (stmt) {
-                       stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-                       stmt->errormsg = "Driver does not support (SET) using bookmarks.";
-                       SC_log_error(func, "", stmt);
-               }
-               if (conn) {
-                       conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-                       conn->errormsg = "Driver does not support (SET) using bookmarks.";
-                       CC_log_error(func, "", conn);
-               }
-               return SQL_ERROR;
+       case SQL_USE_BOOKMARKS:
+
+               if (stmt) stmt->options.use_bookmarks = vParam;
+               if (conn) conn->stmtOptions.use_bookmarks = vParam;
+               break;
 
     default:
                {
@@ -507,6 +500,7 @@ RETCODE SQL_API SQLGetStmtOption(
 {
 static char *func="SQLGetStmtOption";
 StatementClass *stmt = (StatementClass *) hstmt;
+QResultClass *res;
 
        mylog("%s: entering...\n", func);
 
@@ -520,15 +514,39 @@ StatementClass *stmt = (StatementClass *) hstmt;
        }
 
        switch(fOption) {
-       case SQL_GET_BOOKMARK:/* NOT SUPPORTED */
-               stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-               stmt->errormsg = "Driver does not support getting bookmarks.";
-               SC_log_error(func, "", stmt);
-               return SQL_ERROR;
-               break;
-
+       case SQL_GET_BOOKMARK:
        case SQL_ROW_NUMBER:
-               *((SDWORD *) pvParam) = stmt->currTuple + 1;
+
+               res = stmt->result;
+
+               if ( stmt->manual_result || ! globals.use_declarefetch) {
+                       // make sure we're positioned on a valid row
+                       if((stmt->currTuple < 0) ||
+                          (stmt->currTuple >= QR_get_num_tuples(res))) {
+                               stmt->errormsg = "Not positioned on a valid row.";
+                               stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
+                               SC_log_error(func, "", stmt);
+                               return SQL_ERROR;
+                       }
+               }
+               else {
+                       if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
+                               stmt->errormsg = "Not positioned on a valid row.";
+                               stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
+                               SC_log_error(func, "", stmt);
+                               return SQL_ERROR;
+                       }
+               }
+
+               if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF) {
+                       stmt->errormsg = "Operation invalid because use bookmarks not enabled.";
+                       stmt->errornumber = STMT_OPERATION_INVALID;
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+               }
+
+               *((UDWORD *) pvParam) = SC_get_bookmark(stmt);
+               
                break;
 
        case SQL_ASYNC_ENABLE:  /* NOT SUPPORTED */
@@ -583,8 +601,8 @@ StatementClass *stmt = (StatementClass *) hstmt;
                *((SDWORD *) pvParam) = SQL_SC_NON_UNIQUE;
                break;
 
-       case SQL_USE_BOOKMARKS:/* NOT SUPPORTED */
-               *((SDWORD *) pvParam) = SQL_UB_OFF;
+       case SQL_USE_BOOKMARKS:
+               *((SDWORD *) pvParam) = stmt->options.use_bookmarks;
                break;
 
        default:
index 8fcae8020b72fef0e535efa738be13b82ff00e6e..8b095e335d0ce60fcc628ae026219abacf4d1e12 100644 (file)
@@ -39,8 +39,8 @@ typedef UInt4 Oid;
 
 #define DRIVERNAME             "PostgreSQL ODBC"
 #define DBMS_NAME              "PostgreSQL"
-#define DBMS_VERSION           "06.40.0003 PostgreSQL 6.4"
-#define POSTGRESDRIVERVERSION  "06.40.0003"
+#define DBMS_VERSION           "06.40.0004 PostgreSQL 6.4"
+#define POSTGRESDRIVERVERSION  "06.40.0004"
 
 #ifdef WIN32
 #define DRIVER_FILE_NAME               "PSQLODBC.DLL"
@@ -137,6 +137,7 @@ typedef struct StatementOptions_ {
        int scroll_concurrency;
        int retrieve_data;
        int bind_size;                  /* size of each structure if using Row Binding */
+       int use_bookmarks;
 } StatementOptions;
 
 /*     Used to pass extra query info to send_query */
index fc22f3f371e5aa496cf3862901d248f7add153f6..bec4d3b8892a8612fb4b8245752f8bfb3b7f2cd5 100644 (file)
@@ -204,8 +204,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 6,40,0,3
- PRODUCTVERSION 6,40,0,3
+ FILEVERSION 6,40,0,4
+ PRODUCTVERSION 6,40,0,4
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -223,12 +223,12 @@ BEGIN
             VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0"
             VALUE "CompanyName", "Insight Distribution Systems\0"
             VALUE "FileDescription", "PostgreSQL Driver\0"
-            VALUE "FileVersion", " 6.40.0003\0"
+            VALUE "FileVersion", " 6.40.0004\0"
             VALUE "InternalName", "psqlodbc\0"
             VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
             VALUE "OriginalFilename", "psqlodbc.dll\0"
             VALUE "ProductName", "Microsoft Open Database Connectivity\0"
-            VALUE "ProductVersion", " 6.40.0003\0"
+            VALUE "ProductVersion", " 6.40.0004\0"
         END
     END
     BLOCK "VarFileInfo"
index 7b2a0dc04975c517e48b4bc9f68e5015e956b4f1..ece49dd8b08fb9ffa405fa06afb784251c3c4d42 100644 (file)
@@ -610,7 +610,7 @@ int num_cols, num_rows;
 Int4 field_type;
 void *value;
 int result;
-
+char get_bookmark = FALSE;
 
 mylog("SQLGetData: enter, stmt=%u\n", stmt);
 
@@ -635,24 +635,41 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
     }
 
     if (icol == 0) {
-        stmt->errormsg = "Bookmarks are not currently supported.";
-        stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-               SC_log_error(func, "", stmt);
-        return SQL_ERROR;
-    }
 
-    // use zero-based column numbers
-    icol--;
+               if (stmt->options.use_bookmarks == SQL_UB_OFF) {
+                       stmt->errornumber = STMT_COLNUM_ERROR;
+                       stmt->errormsg = "Attempt to retrieve bookmark with bookmark usage disabled";
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+               }
+
+               /*      Make sure it is the bookmark data type */
+               if (fCType != SQL_C_BOOKMARK) {
+                       stmt->errormsg = "Column 0 is not of type SQL_C_BOOKMARK";
+                       stmt->errornumber = STMT_PROGRAM_TYPE_OUT_OF_RANGE;
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+               }
+               
+               get_bookmark = TRUE;
 
-    // make sure the column number is valid
-    num_cols = QR_NumResultCols(res);
-    if (icol >= num_cols) {
-        stmt->errormsg = "Invalid column number.";
-        stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
-               SC_log_error(func, "", stmt);
-        return SQL_ERROR;
     }
 
+       else {
+
+               // use zero-based column numbers
+               icol--;
+
+               // make sure the column number is valid
+               num_cols = QR_NumResultCols(res);
+               if (icol >= num_cols) {
+                       stmt->errormsg = "Invalid column number.";
+                       stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+               }
+       }
+
        if ( stmt->manual_result || ! globals.use_declarefetch) {
                // make sure we're positioned on a valid row
                num_rows = QR_get_num_tuples(res);
@@ -664,13 +681,16 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
                        return SQL_ERROR;
                }
                mylog("     num_rows = %d\n", num_rows);
-               if ( stmt->manual_result) {
-                       value = QR_get_value_manual(res, stmt->currTuple, icol);
-               }
-               else {
-                       value = QR_get_value_backend_row(res, stmt->currTuple, icol);
+
+               if ( ! get_bookmark) {
+                       if ( stmt->manual_result) {
+                               value = QR_get_value_manual(res, stmt->currTuple, icol);
+                       }
+                       else {
+                               value = QR_get_value_backend_row(res, stmt->currTuple, icol);
+                       }
+                       mylog("     value = '%s'\n", value);
                }
-               mylog("     value = '%s'\n", value);
        }
        else { /* its a SOCKET result (backend data) */
                if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
@@ -680,11 +700,21 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
                        return SQL_ERROR;
                }
 
-               value = QR_get_value_backend(res, icol);
+               if ( ! get_bookmark)
+                       value = QR_get_value_backend(res, icol);
 
                mylog("  socket: value = '%s'\n", value);
        }
 
+       if ( get_bookmark) {
+               *((UDWORD *) rgbValue) = SC_get_bookmark(stmt);
+
+               if (pcbValue)
+                       *pcbValue = 4;
+
+               return SQL_SUCCESS;
+       }
+
        field_type = QR_get_field_type(res, icol);
 
        mylog("**** SQLGetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
@@ -761,6 +791,14 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
                return SQL_ERROR;
        }
 
+       /*      Not allowed to bind a bookmark column when using SQLFetch. */
+       if ( stmt->bookmark.buffer) {
+               stmt->errornumber = STMT_COLNUM_ERROR;
+               stmt->errormsg = "Not allowed to bind a bookmark column when using SQLFetch";
+               SC_log_error(func, "", stmt);
+               return SQL_ERROR;
+       }
+
        if (stmt->status == STMT_EXECUTING) {
                stmt->errormsg = "Can't fetch while statement is still executing.";
                stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -831,6 +869,14 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
                return SQL_ERROR;
        }
 
+       /*      If a bookmark colunmn is bound but bookmark usage is off, then error */
+       if (stmt->bookmark.buffer && stmt->options.use_bookmarks == SQL_UB_OFF) {
+               stmt->errornumber = STMT_COLNUM_ERROR;
+               stmt->errormsg = "Attempt to retrieve bookmark with bookmark usage disabled";
+               SC_log_error(func, "", stmt);
+               return SQL_ERROR;
+       }
+
        if (stmt->status == STMT_EXECUTING) {
                stmt->errormsg = "Can't fetch while statement is still executing.";
                stmt->errornumber = STMT_SEQUENCE_ERROR;
@@ -950,6 +996,11 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
                
                break;
 
+       case SQL_FETCH_BOOKMARK:
+
+               stmt->rowset_start = irow - 1;
+               break;
+
        default:
                SC_log_error(func, "Unsupported SQLExtendedFetch Direction", stmt);
                return SQL_ERROR;   
index 86bce41a8f9427e1bc94c94a9f08d4fd0dfde1e9..e8a8b17b36da6b0e665a47428544d445b15e5bfe 100644 (file)
@@ -185,6 +185,7 @@ InitializeStatementOptions(StatementOptions *opt)
        opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
        opt->bind_size = 0;                     /* default is to bind by column */
        opt->retrieve_data = SQL_RD_ON;
+       opt->use_bookmarks = SQL_UB_OFF;
 }
 
 StatementClass *
@@ -213,6 +214,9 @@ StatementClass *rv;
                rv->bindings = NULL;
                rv->bindings_allocated = 0;
 
+               rv->bookmark.buffer = NULL;
+               rv->bookmark.used = NULL;
+
                rv->parameters_allocated = 0;
                rv->parameters = 0;
 
@@ -496,6 +500,9 @@ Int2 lf;
                self->bindings[lf].returntype = SQL_C_CHAR;
        }
 
+       self->bookmark.buffer = NULL;
+       self->bookmark.used = NULL;
+
     return 1;
 }
 
@@ -566,6 +573,15 @@ char rv;
        return rv;
 }
 
+/*     Currently, the driver offers very simple bookmark support -- it is
+       just the current row number.  But it could be more sophisticated 
+       someday, such as mapping a key to a 32 bit value
+*/
+unsigned long
+SC_get_bookmark(StatementClass *self)
+{
+       return (self->currTuple + 1);   
+}
 
 RETCODE
 SC_fetch(StatementClass *self)
@@ -624,6 +640,19 @@ ColumnInfoClass *ci;
        result = SQL_SUCCESS;
        self->last_fetch_count = 1;
 
+       /*      If the bookmark column was bound then return a bookmark.
+               Since this is used with SQLExtendedFetch, and the rowset size 
+               may be greater than 1, and an application can use row or column wise
+               binding, use the code in copy_and_convert_field() to handle that.
+       */
+       if (self->bookmark.buffer) {
+               char buf[32];
+
+               sprintf(buf, "%ld", SC_get_bookmark(self));
+               result = copy_and_convert_field(self, 0, buf, 
+                                                               SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used);
+       }
+
        for (lf=0; lf < num_cols; lf++) {
 
                mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);
index 82d047e1a1a32c848a2b876ffac4589171b3c63f..d2d86e430a259e9b15d6ba3dde6dc5e3f6a29427 100644 (file)
@@ -15,6 +15,7 @@
 #endif
 
 #include "psqlodbc.h"
+#include "bind.h"
 
 #ifndef WIN32
 #include "iodbc.h"
@@ -71,6 +72,8 @@ typedef enum {
 #define STMT_OPERATION_CANCELLED 22
 #define STMT_INVALID_CURSOR_POSITION 23
 #define STMT_VALUE_OUT_OF_RANGE 24
+#define STMT_OPERATION_INVALID 25
+#define STMT_PROGRAM_TYPE_OUT_OF_RANGE 26
 
 /* statement types */
 enum {
@@ -142,6 +145,7 @@ struct StatementClass_ {
 
     /* information on bindings */
     BindInfoClass *bindings;   /* array to store the binding information */
+       BindInfoClass bookmark;
     int bindings_allocated;
 
     /* information on statement parameters */
@@ -207,6 +211,7 @@ RETCODE SC_execute(StatementClass *self);
 RETCODE SC_fetch(StatementClass *self);
 void SC_free_params(StatementClass *self, char option);
 void SC_log_error(char *func, char *desc, StatementClass *self);
+unsigned long SC_get_bookmark(StatementClass *self);
 
 
 #endif