From: Hiroshi Inoue Date: Fri, 21 Sep 2001 07:51:52 +0000 (+0000) Subject: 1) Avoid an overflow of connection string for Access(Microsoft Jet). X-Git-Tag: REL7_2_BETA1~359 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=39dc8ff64f1dd6f5f7b28c99eb7a97e6fb0298f0;p=postgresql 1) Avoid an overflow of connection string for Access(Microsoft Jet). 2) Change to retry lower version in case of "Unsupported frontend procotol". --- diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c index c5d9ab6ab8..7dc3fde0b2 100644 --- a/src/interfaces/odbc/connection.c +++ b/src/interfaces/odbc/connection.c @@ -252,7 +252,10 @@ CC_Constructor() rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */ memset(&rv->connInfo, 0, sizeof(ConnInfo)); -memcpy(&(rv->connInfo.drivers), &globals, sizeof(globals)); +#ifdef DRIVER_CURSOR_IMPLEMENT + rv->connInfo.updatable_cursors = 1; +#endif /* DRIVER_CURSOR_IMPLEMENT */ + memcpy(&(rv->connInfo.drivers), &globals, sizeof(globals)); rv->sock = SOCK_Constructor(rv); if (!rv->sock) return NULL; @@ -278,6 +281,7 @@ memcpy(&(rv->connInfo.drivers), &globals, sizeof(globals)); rv->pg_version_number = .0; rv->pg_version_major = 0; rv->pg_version_minor = 0; + rv->ms_jet = 0; #ifdef MULTIBYTE rv->client_encoding = NULL; rv->server_encoding = NULL; @@ -586,6 +590,7 @@ CC_connect(ConnectionClass *self, char do_password) mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password); +another_version_retry: /* * If the socket was closed for some reason (like a SQLDisconnect, * but no SQLFreeConnect then create a socket now. @@ -690,6 +695,18 @@ CC_connect(ConnectionClass *self, char do_password) self->errornumber = CONN_INVALID_AUTHENTICATION; self->errormsg = msgbuffer; qlog("ERROR from backend during authentication: '%s'\n", self->errormsg); + if (strncmp(msgbuffer, "Unsupported frontend protocol", 29) == 0) + { /* retry older version */ + if (PROTOCOL_63(ci)) + strcpy(ci->protocol, PG62); + else + strcpy(ci->protocol, PG63); + SOCK_Destructor(sock); + self->sock = (SocketClass *) 0; + CC_initialize_pg_version(self); + goto another_version_retry; + } + return 0; case 'R': diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h index fc77bc8a7b..fc3560d352 100644 --- a/src/interfaces/odbc/connection.h +++ b/src/interfaces/odbc/connection.h @@ -160,6 +160,7 @@ typedef struct char translation_option[SMALL_REGISTRY_LEN]; char focus_password; char disallow_premature; + char updatable_cursors; GLOBAL_VALUES drivers; /* moved from driver's option */ } ConnInfo; @@ -274,6 +275,7 @@ struct ConnectionClass_ float pg_version_number; Int2 pg_version_major; Int2 pg_version_minor; + char ms_jet; #ifdef MULTIBYTE char *client_encoding; char *server_encoding; diff --git a/src/interfaces/odbc/dlg_specific.c b/src/interfaces/odbc/dlg_specific.c index aaf9432c4f..c02f633fdb 100644 --- a/src/interfaces/odbc/dlg_specific.c +++ b/src/interfaces/odbc/dlg_specific.c @@ -510,6 +510,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) char got_dsn = (ci->dsn[0] != '\0'); char encoded_conn_settings[LARGE_REGISTRY_LEN]; UWORD hlen; + BOOL abbrev = (len <= 400); /* fundamental info */ sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;PWD=%s", @@ -524,8 +525,9 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) encode(ci->conn_settings, encoded_conn_settings); /* extra info */ - hlen = strlen(connect_string), - sprintf(&connect_string[hlen], + hlen = strlen(connect_string); + if (!abbrev) + sprintf(&connect_string[hlen], ";READONLY=%s;PROTOCOL=%s;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;ROWVERSIONING=%s;SHOWSYSTEMTABLES=%s;CONNSETTINGS=%s;FETCH=%d;SOCKET=%d;UNKNOWNSIZES=%d;MAXVARCHARSIZE=%d;MAXLONGVARCHARSIZE=%d;DEBUG=%d;COMMLOG=%d;OPTIMIZER=%d;KSQO=%d;USEDECLAREFETCH=%d;TEXTASLONGVARCHAR=%d;UNKNOWNSASLONGVARCHAR=%d;BOOLSASCHAR=%d;PARSE=%d;CANCELASFREESTMT=%d;EXTRASYSTABLEPREFIXES=%s", ci->onlyread, ci->protocol, @@ -551,7 +553,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) ci->drivers.cancel_as_freestmt, ci->drivers.extra_systable_prefixes); /* Abbrebiation is needed ? */ - if (strlen(connect_string) >= len) + if (abbrev || strlen(connect_string) >= len) sprintf(&connect_string[hlen], ";A0=%s;A1=%s;A2=%s;A3=%s;A4=%s;A5=%s;A6=%s;A7=%d;A8=%d;A9=%d;B0=%d;B1=%d;B2=%d;B3=%d;B4=%d;B5=%d;B6=%d;B7=%d;B8=%d;B9=%d;C0=%d;C1=%d;C2=%s", ci->onlyread, @@ -630,7 +632,10 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value) else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0) { ci->disallow_premature = atoi(value); - /* strcpy(ci->conn_settings, value); */ + } + else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0) + { + ci->updatable_cursors = atoi(value); } mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password, ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature); @@ -803,6 +808,12 @@ getDSNinfo(ConnInfo *ci, char overwrite) ci->disallow_premature = atoi(temp); } + if (ci->updatable_cursors == 0 || overwrite) + { + SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI); + ci->updatable_cursors = atoi(temp); + } + /* Allow override of odbcinst.ini parameters here */ getCommonDefaults(DSN, ODBC_INI, ci); @@ -916,6 +927,11 @@ writeDSNinfo(const ConnInfo *ci) INI_DISALLOWPREMATURE, temp, ODBC_INI); + sprintf(temp, "%d", ci->updatable_cursors); + SQLWritePrivateProfileString(DSN, + INI_UPDATABLECURSORS, + temp, + ODBC_INI); } diff --git a/src/interfaces/odbc/dlg_specific.h b/src/interfaces/odbc/dlg_specific.h index 8d37eb8a91..6fc04ad2fb 100644 --- a/src/interfaces/odbc/dlg_specific.h +++ b/src/interfaces/odbc/dlg_specific.h @@ -96,6 +96,7 @@ #define INI_TRANSLATIONDLL "TranslationDLL" #define INI_TRANSLATIONOPTION "TranslationOption" #define INI_DISALLOWPREMATURE "DisallowPremature" +#define INI_UPDATABLECURSORS "UpdatableCursors" /* Connection Defaults */ diff --git a/src/interfaces/odbc/drvconn.c b/src/interfaces/odbc/drvconn.c index 80f1d69b7d..781bdd5490 100644 --- a/src/interfaces/odbc/drvconn.c +++ b/src/interfaces/odbc/drvconn.c @@ -1,5 +1,5 @@ /*------- - * Module: drvconn.c + Module: drvconn.c * * Description: This module contains only routines related to * implementing SQLDriverConnect. @@ -88,6 +88,7 @@ PGAPI_DriverConnect( int retval; char password_required = FALSE; int len = 0; + SWORD lenStrout; mylog("%s: entering...\n", func); @@ -211,7 +212,10 @@ dialog: */ result = SQL_SUCCESS; - makeConnectString(connStrOut, ci, cbConnStrOutMax); + lenStrout = cbConnStrOutMax; + if (conn->ms_jet && lenStrout > 255) + lenStrout = 255; + makeConnectString(connStrOut, ci, lenStrout); len = strlen(connStrOut); if (szConnStrOut) diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c index 431a9b1d14..6ff0d0b12e 100644 --- a/src/interfaces/odbc/info.c +++ b/src/interfaces/odbc/info.c @@ -166,19 +166,17 @@ PGAPI_GetInfo( case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */ len = 2; value = SQL_CB_CLOSE; -#ifdef DRIVER_CURSOR_IMPLEMENT - if (!ci->drivers.use_declarefetch) - value = SQL_CB_PRESERVE; -#endif /* DRIVER_CURSOR_IMPLEMENT */ + if (ci->updatable_cursors) + if (!ci->drivers.use_declarefetch) + value = SQL_CB_PRESERVE; break; case SQL_CURSOR_ROLLBACK_BEHAVIOR: /* ODBC 1.0 */ len = 2; value = SQL_CB_CLOSE; -#ifdef DRIVER_CURSOR_IMPLEMENT - if (!ci->drivers.use_declarefetch) - value = SQL_CB_PRESERVE; -#endif /* DRIVER_CURSOR_IMPLEMENT */ + if (ci->updatable_cursors) + if (!ci->drivers.use_declarefetch) + value = SQL_CB_PRESERVE; break; case SQL_DATA_SOURCE_NAME: /* ODBC 1.0 */ @@ -235,7 +233,7 @@ PGAPI_GetInfo( if (dver[0]) { int major, minor; - mylog("REIGISTRY_ODBC_VER = %s\n", dver) + mylog("REGISTRY_ODBC_VER = %s\n", dver) ; if (sscanf(dver, "%x.%x", &major, &minor) >= 2) { @@ -524,6 +522,8 @@ PGAPI_GetInfo( case SQL_POS_OPERATIONS: /* ODBC 2.0 */ len = 4; value = ci->drivers.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH); + if (ci->updatable_cursors) + value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD); break; case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */ @@ -571,7 +571,7 @@ PGAPI_GetInfo( * Driver doesn't support keyset-driven or mixed cursors, so * not much point in saying row updates are supported */ - p = ci->drivers.lie ? "Y" : "N"; + p = (ci->drivers.lie || ci->updatable_cursors) ? "Y" : "N"; break; case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */ @@ -579,7 +579,10 @@ PGAPI_GetInfo( value = ci->drivers.lie ? (SQL_SCCO_READ_ONLY | SQL_SCCO_LOCK | SQL_SCCO_OPT_ROWVER | - SQL_SCCO_OPT_VALUES) : (SQL_SCCO_READ_ONLY); + SQL_SCCO_OPT_VALUES) : + (SQL_SCCO_READ_ONLY); + if (ci->updatable_cursors) + value |= SQL_SCCO_OPT_ROWVER; break; case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */ @@ -588,7 +591,10 @@ PGAPI_GetInfo( SQL_SO_STATIC | SQL_SO_KEYSET_DRIVEN | SQL_SO_DYNAMIC | - SQL_SO_MIXED) : (ci->drivers.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC)); + SQL_SO_MIXED) + : (ci->drivers.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC)); + if (ci->updatable_cursors) + value |= 0; /* SQL_SO_KEYSET_DRIVEN in the furure */ break; case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */ @@ -606,6 +612,8 @@ PGAPI_GetInfo( case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */ len = 4; value = ci->drivers.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0; + if (ci->updatable_cursors) + value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES); break; case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */ diff --git a/src/interfaces/odbc/options.c b/src/interfaces/odbc/options.c index aa18bb1615..a9a0a287fb 100644 --- a/src/interfaces/odbc/options.c +++ b/src/interfaces/odbc/options.c @@ -412,6 +412,15 @@ PGAPI_SetConnectOption( conn->errormsg = "Unknown connect option (Set)"; conn->errornumber = CONN_UNSUPPORTED_OPTION; sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam); + if (fOption == 30002 && vParam) + { + if (strcmp((char *) vParam, "Microsoft Jet") == 0) + { + conn->errornumber = 0; + conn->ms_jet = 1; + return SQL_SUCCESS; + } + } CC_log_error(func, option, conn); return SQL_ERROR; } diff --git a/src/interfaces/odbc/results.c b/src/interfaces/odbc/results.c index 3cfe5fb74b..2475eeef9e 100644 --- a/src/interfaces/odbc/results.c +++ b/src/interfaces/odbc/results.c @@ -164,12 +164,12 @@ PGAPI_NumResultCols( } *pccol = QR_NumResultCols(result); -#ifdef DRIVER_CURSOR_IMPLEMENT - if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY) + /* updatable cursors */ + if (ci->updatable_cursors && + stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY) { *pccol -= 2; } -#endif /* DRIVER_CURSOR_IMPLEMENT */ } return SQL_SUCCESS; @@ -1224,13 +1224,46 @@ PGAPI_MoreResults( #ifdef DRIVER_CURSOR_IMPLEMENT +/* + * Stuff for updatable cursors. + */ +static QResultClass * +positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, const char *tidval) +{ + int i; + QResultClass *qres; + char selstr[4096]; + + sprintf(selstr, "select"); + for (i = 0; i < res_cols; i++) + sprintf(selstr, "%s \"%s\",", selstr, stmt->fi[i]->name); + sprintf(selstr, "%s CTID, OID from \"%s\" where", selstr, stmt->ti[0]->name); + if (tidval) + { + if (latest) + sprintf(selstr, "%s ctid = currtid2('%s', '%s') and", + selstr, stmt->ti[0]->name, tidval); + else + sprintf(selstr, "%s ctid = '%s' and", selstr, tidval); + } + sprintf(selstr, "%s oid = %u", selstr, oid), + mylog("selstr=%s\n", selstr); + qres = CC_send_query(SC_get_conn(stmt), selstr, NULL); + if (qres && QR_aborted(qres)) + { + QR_Destructor(qres); + qres = (QResultClass *) 0; + } + return qres; +} + RETCODE SQL_API SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count) { int i, res_cols; UWORD rcnt, global_ridx; + UInt4 oid; QResultClass *res, *qres; - char selstr[4096]; RETCODE ret = SQL_ERROR; char *tidval, *oidval; @@ -1247,22 +1280,16 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count) stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; return SQL_ERROR; } - strcpy(selstr, "select"); global_ridx = irow + stmt->rowset_start; res_cols = QR_NumResultCols(res); if (!(oidval = QR_get_value_backend_row(res, global_ridx, res_cols - 1))) { return SQL_SUCCESS_WITH_INFO; - } + } + sscanf(oidval, "%u", &oid); tidval = QR_get_value_backend_row(res, global_ridx, res_cols - 2); res_cols -= 2; - for (i = 0; i < res_cols; i++) - sprintf(selstr, "%s \"%s\",", selstr, stmt->fi[i]->name); - sprintf(selstr, "%s CTID, OID from \"%s\" where ctid = currtid2('%s', '%s') and oid = %s", - selstr, stmt->ti[0]->name, stmt->ti[0]->name, tidval, oidval), - mylog("selstr=%s\n", selstr); - qres = CC_send_query(SC_get_conn(stmt), selstr, NULL); - if (qres && QR_command_successful(qres)) + if (qres = positioned_load(stmt, TRUE, res_cols, oid, tidval), qres) { TupleField *tupleo, *tuplen; @@ -1296,22 +1323,20 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count) tupleo[res_cols + 1].len = 0; } } + QR_Destructor(qres); } else if (stmt->errornumber == 0) stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND; - if (qres) - QR_Destructor(qres); if (count) *count = rcnt; return ret; } RETCODE SQL_API -SC_pos_newload(StatementClass *stmt, Int4 oid, const char *tidval) +SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval) { - int i, res_cols; + int i; QResultClass *res, *qres; - char selstr[4096]; RETCODE ret = SQL_ERROR; mylog("positioned new fi=%x ti=%x\n", stmt->fi, stmt->ti); @@ -1324,20 +1349,8 @@ SC_pos_newload(StatementClass *stmt, Int4 oid, const char *tidval) stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; return SQL_ERROR; } - sprintf(selstr, "select"); - res_cols = QR_NumResultCols(res); - res_cols -= 2; - for (i = 0; i < res_cols; i++) - sprintf(selstr, "%s \"%s\",", selstr, stmt->fi[i]->name); - sprintf(selstr, "%s CTID, OID from \"%s\" where", selstr, stmt->ti[0]->name); - if (tidval) - sprintf(selstr, "%s ctid = currtid2('%s', '%s') and", - selstr, stmt->ti[0]->name, tidval); - sprintf(selstr, "%s oid = %u", selstr, oid), - mylog("selstr=%s\n", selstr); - qres = CC_send_query(SC_get_conn(stmt), selstr, NULL); - if (qres && QR_command_successful(qres)) - { + if (qres = positioned_load(stmt, TRUE, QR_NumResultCols(res) - 2, oid, tidval), qres) + { TupleField *tupleo, *tuplen; int count = QR_get_num_tuples(qres); QR_set_position(qres, 0); @@ -1380,10 +1393,9 @@ SC_pos_newload(StatementClass *stmt, Int4 oid, const char *tidval) stmt->errormsg = "the content was changed before updation"; ret = SQL_SUCCESS_WITH_INFO; } + QR_Destructor(qres); /*stmt->currTuple = stmt->rowset_start + irow;*/ } - if (qres) - QR_Destructor(qres); return ret; } @@ -1666,7 +1678,7 @@ SC_pos_add(StatementClass *stmt, else { int addcnt; - Int4 oid; + UInt4 oid; const char *cmdstr = QR_get_command(qstmt->result); if (cmdstr && sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 && @@ -1696,6 +1708,9 @@ SC_pos_add(StatementClass *stmt, PGAPI_FreeStmt(hstmt, SQL_DROP); return ret; } +/* + * Stuff for updatable cursors end. + */ #endif /* DRIVER_CURSOR_IMPLEMENT */ /*