Commit 0b644ad3 authored by Byron Nikolaidis's avatar Byron Nikolaidis

Update 06-40-0004 -- Add Bookmark support!

parent 97b88f1c
...@@ -162,13 +162,6 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol); ...@@ -162,13 +162,6 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
return SQL_INVALID_HANDLE; 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); SC_clear_error(stmt);
...@@ -179,6 +172,28 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol); ...@@ -179,6 +172,28 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
return SQL_ERROR; 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 // allocate enough bindings if not already done
// Most likely, execution of a statement would have setup the // Most likely, execution of a statement would have setup the
// necessary bindings. But some apps call BindCol before any // necessary bindings. But some apps call BindCol before any
......
...@@ -190,6 +190,11 @@ int status; ...@@ -190,6 +190,11 @@ int status;
case STMT_VALUE_OUT_OF_RANGE: case STMT_VALUE_OUT_OF_RANGE:
strcpy(szSqlState, "22003"); strcpy(szSqlState, "22003");
break; break;
case STMT_OPERATION_INVALID:
strcpy(szSqlState, "S1011");
break;
default: default:
strcpy(szSqlState, "S1000"); strcpy(szSqlState, "S1000");
// also a general error // also a general error
......
...@@ -107,8 +107,9 @@ RETCODE result; ...@@ -107,8 +107,9 @@ RETCODE result;
break; break;
case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */ case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
/* very simple bookmark support */
len = 4; len = 4;
value = 0; value = globals.use_declarefetch ? 0 : (SQL_BP_SCROLL);
break; break;
case SQL_COLUMN_ALIAS: /* ODBC 2.0 */ case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
...@@ -221,7 +222,8 @@ RETCODE result; ...@@ -221,7 +222,8 @@ RETCODE result;
SQL_FD_FETCH_LAST | SQL_FD_FETCH_LAST |
SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_PRIOR |
SQL_FD_FETCH_ABSOLUTE | SQL_FD_FETCH_ABSOLUTE |
SQL_FD_FETCH_RELATIVE); SQL_FD_FETCH_RELATIVE |
SQL_FD_FETCH_BOOKMARK);
break; break;
case SQL_FILE_USAGE: /* ODBC 2.0 */ case SQL_FILE_USAGE: /* ODBC 2.0 */
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "environ.h" #include "environ.h"
#include "connection.h" #include "connection.h"
#include "statement.h" #include "statement.h"
#include "qresult.h"
extern GLOBAL_VALUES globals; extern GLOBAL_VALUES globals;
...@@ -189,7 +190,6 @@ char changed = FALSE; ...@@ -189,7 +190,6 @@ char changed = FALSE;
if (conn) conn->stmtOptions.rowset_size = vParam; if (conn) conn->stmtOptions.rowset_size = vParam;
if (stmt) stmt->options.rowset_size = vParam; if (stmt) stmt->options.rowset_size = vParam;
break; break;
case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */ case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
...@@ -205,18 +205,11 @@ char changed = FALSE; ...@@ -205,18 +205,11 @@ char changed = FALSE;
} }
return SQL_ERROR; return SQL_ERROR;
case SQL_USE_BOOKMARKS: /* NOT SUPPORTED */ case SQL_USE_BOOKMARKS:
if (stmt) {
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; if (stmt) stmt->options.use_bookmarks = vParam;
stmt->errormsg = "Driver does not support (SET) using bookmarks."; if (conn) conn->stmtOptions.use_bookmarks = vParam;
SC_log_error(func, "", stmt); break;
}
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;
default: default:
{ {
...@@ -507,6 +500,7 @@ RETCODE SQL_API SQLGetStmtOption( ...@@ -507,6 +500,7 @@ RETCODE SQL_API SQLGetStmtOption(
{ {
static char *func="SQLGetStmtOption"; static char *func="SQLGetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
mylog("%s: entering...\n", func); mylog("%s: entering...\n", func);
...@@ -520,15 +514,39 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -520,15 +514,39 @@ StatementClass *stmt = (StatementClass *) hstmt;
} }
switch(fOption) { switch(fOption) {
case SQL_GET_BOOKMARK:/* NOT SUPPORTED */ case SQL_GET_BOOKMARK:
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; case SQL_ROW_NUMBER:
stmt->errormsg = "Driver does not support getting bookmarks.";
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); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
break; }
}
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);
case SQL_ROW_NUMBER:
*((SDWORD *) pvParam) = stmt->currTuple + 1;
break; break;
case SQL_ASYNC_ENABLE: /* NOT SUPPORTED */ case SQL_ASYNC_ENABLE: /* NOT SUPPORTED */
...@@ -583,8 +601,8 @@ StatementClass *stmt = (StatementClass *) hstmt; ...@@ -583,8 +601,8 @@ StatementClass *stmt = (StatementClass *) hstmt;
*((SDWORD *) pvParam) = SQL_SC_NON_UNIQUE; *((SDWORD *) pvParam) = SQL_SC_NON_UNIQUE;
break; break;
case SQL_USE_BOOKMARKS:/* NOT SUPPORTED */ case SQL_USE_BOOKMARKS:
*((SDWORD *) pvParam) = SQL_UB_OFF; *((SDWORD *) pvParam) = stmt->options.use_bookmarks;
break; break;
default: default:
......
...@@ -39,8 +39,8 @@ typedef UInt4 Oid; ...@@ -39,8 +39,8 @@ typedef UInt4 Oid;
#define DRIVERNAME "PostgreSQL ODBC" #define DRIVERNAME "PostgreSQL ODBC"
#define DBMS_NAME "PostgreSQL" #define DBMS_NAME "PostgreSQL"
#define DBMS_VERSION "06.40.0003 PostgreSQL 6.4" #define DBMS_VERSION "06.40.0004 PostgreSQL 6.4"
#define POSTGRESDRIVERVERSION "06.40.0003" #define POSTGRESDRIVERVERSION "06.40.0004"
#ifdef WIN32 #ifdef WIN32
#define DRIVER_FILE_NAME "PSQLODBC.DLL" #define DRIVER_FILE_NAME "PSQLODBC.DLL"
...@@ -137,6 +137,7 @@ typedef struct StatementOptions_ { ...@@ -137,6 +137,7 @@ typedef struct StatementOptions_ {
int scroll_concurrency; int scroll_concurrency;
int retrieve_data; int retrieve_data;
int bind_size; /* size of each structure if using Row Binding */ int bind_size; /* size of each structure if using Row Binding */
int use_bookmarks;
} StatementOptions; } StatementOptions;
/* Used to pass extra query info to send_query */ /* Used to pass extra query info to send_query */
......
...@@ -204,8 +204,8 @@ END ...@@ -204,8 +204,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 6,40,0,3 FILEVERSION 6,40,0,4
PRODUCTVERSION 6,40,0,3 PRODUCTVERSION 6,40,0,4
FILEFLAGSMASK 0x3L FILEFLAGSMASK 0x3L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
...@@ -223,12 +223,12 @@ BEGIN ...@@ -223,12 +223,12 @@ BEGIN
VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0" VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0"
VALUE "CompanyName", "Insight Distribution Systems\0" VALUE "CompanyName", "Insight Distribution Systems\0"
VALUE "FileDescription", "PostgreSQL Driver\0" VALUE "FileDescription", "PostgreSQL Driver\0"
VALUE "FileVersion", " 6.40.0003\0" VALUE "FileVersion", " 6.40.0004\0"
VALUE "InternalName", "psqlodbc\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 "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 "OriginalFilename", "psqlodbc.dll\0"
VALUE "ProductName", "Microsoft Open Database Connectivity\0" VALUE "ProductName", "Microsoft Open Database Connectivity\0"
VALUE "ProductVersion", " 6.40.0003\0" VALUE "ProductVersion", " 6.40.0004\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
......
...@@ -610,7 +610,7 @@ int num_cols, num_rows; ...@@ -610,7 +610,7 @@ int num_cols, num_rows;
Int4 field_type; Int4 field_type;
void *value; void *value;
int result; int result;
char get_bookmark = FALSE;
mylog("SQLGetData: enter, stmt=%u\n", stmt); mylog("SQLGetData: enter, stmt=%u\n", stmt);
...@@ -635,12 +635,28 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt); ...@@ -635,12 +635,28 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
} }
if (icol == 0) { if (icol == 0) {
stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; 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); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
get_bookmark = TRUE;
}
else {
// use zero-based column numbers // use zero-based column numbers
icol--; icol--;
...@@ -652,6 +668,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt); ...@@ -652,6 +668,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
}
if ( stmt->manual_result || ! globals.use_declarefetch) { if ( stmt->manual_result || ! globals.use_declarefetch) {
// make sure we're positioned on a valid row // make sure we're positioned on a valid row
...@@ -664,6 +681,8 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt); ...@@ -664,6 +681,8 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
mylog(" num_rows = %d\n", num_rows); mylog(" num_rows = %d\n", num_rows);
if ( ! get_bookmark) {
if ( stmt->manual_result) { if ( stmt->manual_result) {
value = QR_get_value_manual(res, stmt->currTuple, icol); value = QR_get_value_manual(res, stmt->currTuple, icol);
} }
...@@ -672,6 +691,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt); ...@@ -672,6 +691,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
} }
mylog(" value = '%s'\n", value); mylog(" value = '%s'\n", value);
} }
}
else { /* its a SOCKET result (backend data) */ else { /* its a SOCKET result (backend data) */
if (stmt->currTuple == -1 || ! res || ! res->tupleField) { if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
stmt->errormsg = "Not positioned on a valid row for GetData."; stmt->errormsg = "Not positioned on a valid row for GetData.";
...@@ -680,11 +700,21 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt); ...@@ -680,11 +700,21 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
if ( ! get_bookmark)
value = QR_get_value_backend(res, icol); value = QR_get_value_backend(res, icol);
mylog(" socket: value = '%s'\n", value); 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); 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); 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); ...@@ -761,6 +791,14 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
return SQL_ERROR; 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) { if (stmt->status == STMT_EXECUTING) {
stmt->errormsg = "Can't fetch while statement is still executing."; stmt->errormsg = "Can't fetch while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
...@@ -831,6 +869,14 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt); ...@@ -831,6 +869,14 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
return SQL_ERROR; 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) { if (stmt->status == STMT_EXECUTING) {
stmt->errormsg = "Can't fetch while statement is still executing."; stmt->errormsg = "Can't fetch while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errornumber = STMT_SEQUENCE_ERROR;
...@@ -950,6 +996,11 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt); ...@@ -950,6 +996,11 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
break; break;
case SQL_FETCH_BOOKMARK:
stmt->rowset_start = irow - 1;
break;
default: default:
SC_log_error(func, "Unsupported SQLExtendedFetch Direction", stmt); SC_log_error(func, "Unsupported SQLExtendedFetch Direction", stmt);
return SQL_ERROR; return SQL_ERROR;
......
...@@ -185,6 +185,7 @@ InitializeStatementOptions(StatementOptions *opt) ...@@ -185,6 +185,7 @@ InitializeStatementOptions(StatementOptions *opt)
opt->cursor_type = SQL_CURSOR_FORWARD_ONLY; opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
opt->bind_size = 0; /* default is to bind by column */ opt->bind_size = 0; /* default is to bind by column */
opt->retrieve_data = SQL_RD_ON; opt->retrieve_data = SQL_RD_ON;
opt->use_bookmarks = SQL_UB_OFF;
} }
StatementClass * StatementClass *
...@@ -213,6 +214,9 @@ StatementClass *rv; ...@@ -213,6 +214,9 @@ StatementClass *rv;
rv->bindings = NULL; rv->bindings = NULL;
rv->bindings_allocated = 0; rv->bindings_allocated = 0;
rv->bookmark.buffer = NULL;
rv->bookmark.used = NULL;
rv->parameters_allocated = 0; rv->parameters_allocated = 0;
rv->parameters = 0; rv->parameters = 0;
...@@ -496,6 +500,9 @@ Int2 lf; ...@@ -496,6 +500,9 @@ Int2 lf;
self->bindings[lf].returntype = SQL_C_CHAR; self->bindings[lf].returntype = SQL_C_CHAR;
} }
self->bookmark.buffer = NULL;
self->bookmark.used = NULL;
return 1; return 1;
} }
...@@ -566,6 +573,15 @@ char rv; ...@@ -566,6 +573,15 @@ char rv;
return 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 RETCODE
SC_fetch(StatementClass *self) SC_fetch(StatementClass *self)
...@@ -624,6 +640,19 @@ ColumnInfoClass *ci; ...@@ -624,6 +640,19 @@ ColumnInfoClass *ci;
result = SQL_SUCCESS; result = SQL_SUCCESS;
self->last_fetch_count = 1; 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++) { 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); mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#endif #endif
#include "psqlodbc.h" #include "psqlodbc.h"
#include "bind.h"
#ifndef WIN32 #ifndef WIN32
#include "iodbc.h" #include "iodbc.h"
...@@ -71,6 +72,8 @@ typedef enum { ...@@ -71,6 +72,8 @@ typedef enum {
#define STMT_OPERATION_CANCELLED 22 #define STMT_OPERATION_CANCELLED 22
#define STMT_INVALID_CURSOR_POSITION 23 #define STMT_INVALID_CURSOR_POSITION 23
#define STMT_VALUE_OUT_OF_RANGE 24 #define STMT_VALUE_OUT_OF_RANGE 24
#define STMT_OPERATION_INVALID 25
#define STMT_PROGRAM_TYPE_OUT_OF_RANGE 26
/* statement types */ /* statement types */
enum { enum {
...@@ -142,6 +145,7 @@ struct StatementClass_ { ...@@ -142,6 +145,7 @@ struct StatementClass_ {
/* information on bindings */ /* information on bindings */
BindInfoClass *bindings; /* array to store the binding information */ BindInfoClass *bindings; /* array to store the binding information */
BindInfoClass bookmark;
int bindings_allocated; int bindings_allocated;
/* information on statement parameters */ /* information on statement parameters */
...@@ -207,6 +211,7 @@ RETCODE SC_execute(StatementClass *self); ...@@ -207,6 +211,7 @@ RETCODE SC_execute(StatementClass *self);
RETCODE SC_fetch(StatementClass *self); RETCODE SC_fetch(StatementClass *self);
void SC_free_params(StatementClass *self, char option); void SC_free_params(StatementClass *self, char option);
void SC_log_error(char *func, char *desc, StatementClass *self); void SC_log_error(char *func, char *desc, StatementClass *self);
unsigned long SC_get_bookmark(StatementClass *self);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment