From 61d8cf283e73bd08d10785de03be2fce75fcda1a Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Fri, 21 Jun 2013 12:45:40 +0900 Subject: [PATCH] Reduce the memory usage of ConnectinClass objects by changing their large fixed length text fields to variable ones. Because changes are applied to percent-encoded fields this time, password field is also a target of this change. --- connection.c | 124 +++++++++++++++++++++++++++++++------------------ connection.h | 11 +++-- descriptor.h | 71 ---------------------------- dlg_specific.c | 109 ++++++++++++++++++++++++++----------------- dlg_specific.h | 2 +- dlg_wingui.c | 25 +++++++--- drvconn.c | 2 +- multibyte.c | 8 ++-- multibyte.h | 5 +- psqlodbc.c | 17 +++++++ psqlodbc.h | 79 ++++++++++++++++++++++++++++++- results.c | 2 +- setup.c | 6 +-- 13 files changed, 280 insertions(+), 181 deletions(-) diff --git a/connection.c b/connection.c index 6e9937f..2b7de7a 100644 --- a/connection.c +++ b/connection.c @@ -14,6 +14,11 @@ */ /* Multibyte support Eiji Tokuya 2001-03-15 */ +/* TryEnterCritiaclSection needs the following #define */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif /* _WIN32_WINNT */ + #include "connection.h" #ifndef NOT_USE_LIBPQ #include @@ -116,7 +121,7 @@ PGAPI_Connect( ConnInfo *ci; CSTR func = "PGAPI_Connect"; RETCODE ret = SQL_SUCCESS; - char fchar; + char fchar, *tmpstr; mylog("%s: entering..cbDSN=%hi.\n", func, cbDSN); @@ -127,11 +132,11 @@ PGAPI_Connect( } ci = &conn->connInfo; + CC_conninfo_init(ci, COPY_GLOBALS); make_string(szDSN, cbDSN, ci->dsn, sizeof(ci->dsn)); /* get the values for the DSN from the registry */ - memcpy(&ci->drivers, &globals, sizeof(globals)); getDSNinfo(ci, CONN_OVERWRITE); logs_on_off(1, ci->drivers.debug, ci->drivers.commlog); /* initialize pg_version from connInfo.protocol */ @@ -145,15 +150,18 @@ PGAPI_Connect( make_string(szUID, cbUID, ci->username, sizeof(ci->username)); if ('\0' == ci->username[0]) /* an empty string is specified */ ci->username[0] = fchar; /* restore the original username */ - fchar = ci->password[0]; - make_string(szAuthStr, cbAuthStr, ci->password, sizeof(ci->password)); - if ('\0' == ci->password[0]) /* an empty string is specified */ - ci->password[0] = fchar; /* restore the original password */ + tmpstr = make_string(szAuthStr, cbAuthStr, NULL, 0); + if (tmpstr) + { + if (tmpstr[0]) /* non-empty string is specified */ + STR_TO_NAME(ci->password, tmpstr); + free(tmpstr); + } /* fill in any defaults */ getDSNdefaults(ci); - qlog("conn = %p, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password ? "xxxxx" : ""); + qlog("conn = %p, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, NAME_IS_VALID(ci->password) ? "xxxxx" : ""); if ((fchar = CC_connect(conn, AUTH_REQ_OK, NULL)) <= 0) { @@ -259,30 +267,56 @@ PGAPI_FreeConnect( return SQL_SUCCESS; } +static void +CC_conninfo_release(ConnInfo *conninfo) +{ + NULL_THE_NAME(conninfo->password); + NULL_THE_NAME(conninfo->conn_settings); + finalize_globals(&conninfo->drivers); +} + void -CC_conninfo_init(ConnInfo *conninfo) +CC_conninfo_init(ConnInfo *conninfo, UInt4 option) { - memset(conninfo, 0, sizeof(ConnInfo)); - conninfo->disallow_premature = -1; - conninfo->allow_keyset = -1; - conninfo->lf_conversion = -1; - conninfo->true_is_minus1 = -1; - conninfo->int8_as = -101; - conninfo->bytea_as_longvarbinary = -1; - conninfo->use_server_side_prepare = -1; - conninfo->lower_case_identifier = -1; - conninfo->rollback_on_error = -1; - conninfo->force_abbrev_connstr = -1; - conninfo->bde_environment = -1; - conninfo->fake_mss = -1; - conninfo->cvt_null_date_string = -1; - conninfo->autocommit_public = SQL_AUTOCOMMIT_ON; - conninfo->accessible_only = -1; - conninfo->gssauth_use_gssapi = -1; + CSTR func = "CC_conninfo_init"; + mylog("%s opt=%d\n", func, option); + + if (0 != (CLEANUP_FOR_REUSE & option)) + CC_conninfo_release(conninfo); + memset(conninfo, 0, sizeof(ConnInfo)); + conninfo->disallow_premature = -1; + conninfo->allow_keyset = -1; + conninfo->lf_conversion = -1; + conninfo->true_is_minus1 = -1; + conninfo->int8_as = -101; + conninfo->bytea_as_longvarbinary = -1; + conninfo->use_server_side_prepare = -1; + conninfo->lower_case_identifier = -1; + conninfo->rollback_on_error = -1; + conninfo->force_abbrev_connstr = -1; + conninfo->bde_environment = -1; + conninfo->fake_mss = -1; + conninfo->cvt_null_date_string = -1; + conninfo->autocommit_public = SQL_AUTOCOMMIT_ON; + conninfo->accessible_only = -1; + conninfo->gssauth_use_gssapi = -1; #ifdef _HANDLE_ENLIST_IN_DTC_ - conninfo->xa_opt = -1; + conninfo->xa_opt = -1; #endif /* _HANDLE_ENLIST_IN_DTC_ */ - memcpy(&(conninfo->drivers), &globals, sizeof(globals)); + if (0 != (COPY_GLOBALS & option)) + copy_globals(&(conninfo->drivers), &globals); +} + +void +CC_copy_conninfo(ConnInfo *ci, const ConnInfo *sci) +{ + memcpy(ci, sci, sizeof(ConnInfo)); + SET_NAME_DIRECTLY(ci->conn_settings, NULL); + SET_NAME_DIRECTLY(ci->drivers.drivername, NULL); + SET_NAME_DIRECTLY(ci->drivers.conn_settings, NULL); + NAME_TO_NAME(ci->conn_settings, sci->conn_settings); + NAME_TO_NAME(ci->drivers.drivername, sci->drivers.drivername); + NAME_TO_NAME(ci->drivers.conn_settings, sci->drivers.conn_settings); } #ifdef WIN32 @@ -316,7 +350,7 @@ CC_Constructor() rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */ rv->stmt_in_extquery = NULL; - CC_conninfo_init(&(rv->connInfo)); + CC_conninfo_init(&(rv->connInfo), COPY_GLOBALS); rv->sock = SOCK_Constructor(rv); if (!rv->sock) goto cleanup; @@ -399,6 +433,7 @@ CC_Destructor(ConnectionClass *self) NULL_THE_NAME(self->schemaIns); NULL_THE_NAME(self->tableIns); + CC_conninfo_release(&self->connInfo); if (self->__error_message) free(self->__error_message); DELETE_CONN_CS(self); @@ -661,7 +696,7 @@ CC_cleanup(ConnectionClass *self) self->status = CONN_NOT_CONNECTED; self->transact_status = CONN_IN_AUTOCOMMIT; self->stmt_in_extquery = NULL; - CC_conninfo_init(&(self->connInfo)); + CC_conninfo_init(&(self->connInfo), CLEANUP_FOR_REUSE); if (self->original_client_encoding) { free(self->original_client_encoding); @@ -747,10 +782,10 @@ md5_auth_send(ConnectionClass *self, const char *salt) SocketClass *sock = self->sock; size_t md5len; -inolog("md5 pwd=%s user=%s salt=%02x%02x%02x%02x%02x\n", ci->password, ci->username, (UCHAR)salt[0], (UCHAR)salt[1], (UCHAR)salt[2], (UCHAR)salt[3], (UCHAR)salt[4]); +inolog("md5 pwd=%s user=%s salt=%02x%02x%02x%02x%02x\n", PRINT_NAME(ci->password), ci->username, (UCHAR)salt[0], (UCHAR)salt[1], (UCHAR)salt[2], (UCHAR)salt[3], (UCHAR)salt[4]); if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1))) return 1; - if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1)) + if (!EncryptMD5(SAFE_NAME(ci->password), ci->username, strlen(ci->username), pwd1)) { free(pwd1); return 1; @@ -1120,9 +1155,9 @@ mylog("!!! usrname=%s server=%s\n", usrname, ci->server); opts[cnt] = "sslmode"; vals[cnt++] = ci->sslmode; } - if (ci->password[0]) + if (NAME_IS_VALID(ci->password)) { - opts[cnt] = "password"; vals[cnt++] = ci->password; + opts[cnt] = "password"; vals[cnt++] = SAFE_NAME(ci->password); } if (ci->gssauth_use_gssapi) { @@ -1341,7 +1376,7 @@ static char CC_initial_log(ConnectionClass *self, const char *func) self->ccsc = pg_CS_code(self->original_client_encoding); qlog(" extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n", ci->drivers.extra_systable_prefixes, - ci->drivers.conn_settings, + PRINT_NAME(ci->drivers.conn_settings), encoding ? encoding : ""); if (self->status != CONN_NOT_CONNECTED) { @@ -1349,13 +1384,12 @@ static char CC_initial_log(ConnectionClass *self, const char *func) return 0; } - mylog("%s: DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", func, ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password ? "xxxxx" : ""); + mylog("%s: DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", func, ci->dsn, ci->server, ci->port, ci->database, ci->username, NAME_IS_VALID(ci->password) ? "xxxxx" : ""); if (ci->port[0] == '\0') { - CC_set_error(self, CONN_INIREAD_ERROR, "Missing port in call to CC_connect.", func); + CC_set_error(self, CONN_INIREAD_ERROR, "Missing port name in call to CC_connect.", func); return 0; - } #ifdef WIN32 if (ci->server[0] == '\0') @@ -1773,7 +1807,7 @@ inolog("Ekita retry=%d\n", retry); case AUTH_REQ_PASSWORD: mylog("in AUTH_REQ_PASSWORD\n"); - if (ci->password[0] == '\0') + if (NAME_IS_NULL(ci->password)) { CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func); ret = -areq; /* need password */ @@ -1784,8 +1818,8 @@ inolog("Ekita retry=%d\n", retry); if (PROTOCOL_74(&(self->connInfo))) SOCK_put_char(sock, 'p'); - SOCK_put_int(sock, (Int4) (4 + strlen(ci->password) + 1), 4); - SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1); + SOCK_put_int(sock, (Int4) (4 + strlen(SAFE_NAME(ci->password)) + 1), 4); + SOCK_put_n_char(sock, SAFE_NAME(ci->password), strlen(SAFE_NAME(ci->password)) + 1); sockerr = SOCK_flush_output(sock); mylog("past flush %dbytes\n", sockerr); @@ -1796,7 +1830,7 @@ inolog("Ekita retry=%d\n", retry); goto error_proc; case AUTH_REQ_MD5: mylog("in AUTH_REQ_MD5\n"); - if (ci->password[0] == '\0') + if (NAME_IS_NULL(ci->password)) { CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func); if (salt_para) @@ -3605,9 +3639,9 @@ CC_send_settings(ConnectionClass *self) stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */ /* Global settings */ - if (ci->drivers.conn_settings[0] != '\0') + if (NAME_IS_VALID(ci->drivers.conn_settings)) { - cs = strdup(ci->drivers.conn_settings); + cs = strdup(GET_NAME(ci->drivers.conn_settings)); #ifdef HAVE_STRTOK_R ptr = strtok_r(cs, semi_colon, &last); #else @@ -3632,9 +3666,9 @@ CC_send_settings(ConnectionClass *self) } /* Per Datasource settings */ - if (ci->conn_settings[0] != '\0') + if (NAME_IS_VALID(ci->conn_settings)) { - cs = strdup(ci->conn_settings); + cs = strdup(GET_NAME(ci->conn_settings)); #ifdef HAVE_STRTOK_R ptr = strtok_r(cs, semi_colon, &last); #else diff --git a/connection.h b/connection.h index f0f6c18..0215957 100644 --- a/connection.h +++ b/connection.h @@ -285,8 +285,7 @@ typedef struct char server[MEDIUM_REGISTRY_LEN]; char database[MEDIUM_REGISTRY_LEN]; char username[MEDIUM_REGISTRY_LEN]; - char password[MEDIUM_REGISTRY_LEN]; - char conn_settings[LARGE_REGISTRY_LEN]; + pgNAME password; char protocol[SMALL_REGISTRY_LEN]; char port[SMALL_REGISTRY_LEN]; char sslmode[16]; @@ -298,6 +297,7 @@ typedef struct char translation_dll[MEDIUM_REGISTRY_LEN]; char translation_option[SMALL_REGISTRY_LEN]; char focus_password; + pgNAME conn_settings; signed char disallow_premature; signed char allow_keyset; signed char updatable_cursors; @@ -512,7 +512,12 @@ struct ConnectionClass_ /* prototypes */ ConnectionClass *CC_Constructor(void); -void CC_conninfo_init(ConnInfo *conninfo); +enum { /* CC_conninfo_init option */ + CLEANUP_FOR_REUSE = 1L /* reuse the info */ + ,COPY_GLOBALS = (1L << 1) /* copy globals to drivers */ +}; +void CC_conninfo_init(ConnInfo *conninfo, UInt4 option); +void CC_copy_conninfo(ConnInfo *to, const ConnInfo *from); char CC_Destructor(ConnectionClass *self); int CC_cursor_count(ConnectionClass *self); char CC_cleanup(ConnectionClass *self); diff --git a/descriptor.h b/descriptor.h index f367311..d52500e 100644 --- a/descriptor.h +++ b/descriptor.h @@ -11,77 +11,6 @@ #include "psqlodbc.h" -typedef struct -{ - char *name; -} pgNAME; -#define GET_NAME(the_name) ((the_name).name) -#define SAFE_NAME(the_name) ((the_name).name ? (the_name).name : NULL_STRING) -#define PRINT_NAME(the_name) ((the_name).name ? (the_name).name : PRINT_NULL) -#define NAME_IS_NULL(the_name) (NULL == (the_name).name) -#define NAME_IS_VALID(the_name) (NULL != (the_name).name) -#define INIT_NAME(the_name) ((the_name).name = NULL) -#define NULL_THE_NAME(the_name) \ -do { \ - if ((the_name).name) free((the_name).name); \ - (the_name).name = NULL; \ -} while (0) -#define STR_TO_NAME(the_name, str) \ -do { \ - if ((the_name).name) \ - free((the_name).name); \ - (the_name).name = (str ? strdup((str)) : NULL); \ -} while (0) -/* - * a modified version of macro STR_TO_NAME to suppress compiler warnings - * when the compiler may confirm str != NULL. - */ -#define STRX_TO_NAME(the_name, str) \ -do { \ - if ((the_name).name) \ - free((the_name).name); \ - (the_name).name = strdup((str)); \ -} while (0) - -#define STRN_TO_NAME(the_name, str, n) \ -do { \ - if ((the_name).name) \ - free((the_name).name); \ - if (str) \ - { \ - (the_name).name = malloc(n + 1); \ - memcpy((the_name).name, str, n); \ - (the_name).name[n] = '\0'; \ - } \ - else \ - (the_name).name = NULL; \ -} while (0) -#define NAME_TO_STR(str, the_name) \ -do {\ - if ((the_name).name) strcpy(str, (the_name).name); \ - else *str = '\0'; \ -} while (0) -#define NAME_TO_NAME(to, from) \ -do { \ - if ((to).name) \ - free((to).name); \ - if ((from).name) \ - (to).name = strdup(from.name); \ - else \ - (to).name = NULL; \ -} while (0) -#define MOVE_NAME(to, from) \ -do { \ - if ((to).name) \ - free((to).name); \ - (to).name = (from).name; \ - (from).name = NULL; \ -} while (0) -#define SET_NAME(the_name, str) ((the_name).name = (str)) - -#define NAMECMP(name1, name2) (strcmp(SAFE_NAME(name1), SAFE_NAME(name2))) -#define NAMEICMP(name1, name2) (stricmp(SAFE_NAME(name1), SAFE_NAME(name2))) - enum { TI_UPDATABLE = 1L ,TI_HASOIDS_CHECKED = (1L << 1) diff --git a/dlg_specific.c b/dlg_specific.c index d7ca042..cf23136 100644 --- a/dlg_specific.c +++ b/dlg_specific.c @@ -27,9 +27,9 @@ extern GLOBAL_VALUES globals; -static void encode(const UCHAR *in, UCHAR *out, int outlen); -static void decode(const UCHAR *in, UCHAR *out, int outlen); -static void decode_or_remove_braces(const UCHAR *in, UCHAR *out, int outlen); +static void encode(const pgNAME, UCHAR *out, int outlen); +static pgNAME decode(const UCHAR *in); +static pgNAME decode_or_remove_braces(const UCHAR *in); #define OVR_EXTRA_BITS (BIT_FORCEABBREVCONNSTR | BIT_FAKE_MSS | BIT_BDE_ENVIRONMENT | BIT_CVT_NULL_DATE | BIT_ACCESSIBLE_ONLY) UInt4 getExtraOptions(const ConnInfo *ci) @@ -498,7 +498,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value) strcpy(ci->username, value); else if (stricmp(attribute, INI_PASSWORD) == 0 || stricmp(attribute, "pwd") == 0) - decode_or_remove_braces(value, ci->password, sizeof(ci->password)); + ci->password = decode_or_remove_braces(value); else if (stricmp(attribute, INI_PORT) == 0) strcpy(ci->port, value); @@ -539,17 +539,18 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value) else if (stricmp(attribute, INI_CONNSETTINGS) == 0 || stricmp(attribute, ABBR_CONNSETTINGS) == 0) { + /* We can use the conn_settings directly when they are enclosed with braces */ if ('{' == *value) { size_t len; - strncpy_null(ci->conn_settings, value + 1, sizeof(ci->conn_settings)); - len = strlen(ci->conn_settings); - if (len > 0 && '}' == ci->conn_settings[len - 1]) - ci->conn_settings[len - 1] = '\0'; + len = strlen(value + 1); + if (len > 0 && '}' == value[len]) + len--; + STRN_TO_NAME(ci->conn_settings, value + 1, len); } else - decode(value, ci->conn_settings, sizeof(ci->conn_settings)); + ci->conn_settings = decode(value); } else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, ABBR_DISALLOWPREMATURE) == 0) ci->disallow_premature = atoi(value); @@ -630,7 +631,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value) else found = FALSE; - mylog("%s: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", func, ci->dsn, ci->server, ci->database, ci->username, ci->password ? "xxxxx" : "", ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature); + mylog("%s: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", func, ci->dsn, ci->server, ci->database, ci->username, NAME_IS_VALID(ci->password) ? "xxxxx" : "", ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature); return found; } @@ -812,7 +813,7 @@ getDSNinfo(ConnInfo *ci, char overwrite) if (ci->drivername[0] == '\0' || overwrite) { getDriverNameFromDSN(DSN, ci->drivername, sizeof(ci->drivername)); - if (ci->drivername[0] && stricmp(ci->drivername, DBMS_NAME)) + if (ci->drivername[0] && stricmp(ci->drivername, SAFE_NAME(ci->drivers.drivername))) getCommonDefaults(ci->drivername, ODBCINST_INI, ci); } @@ -830,10 +831,10 @@ getDSNinfo(ConnInfo *ci, char overwrite) if (ci->username[0] == '\0' || overwrite) SQLGetPrivateProfileString(DSN, INI_USERNAME, "", ci->username, sizeof(ci->username), ODBC_INI); - if (ci->password[0] == '\0' || overwrite) + if (NAME_IS_NULL(ci->password) || overwrite) { SQLGetPrivateProfileString(DSN, INI_PASSWORD, "", encoded_item, sizeof(encoded_item), ODBC_INI); - decode(encoded_item, ci->password, sizeof(ci->password)); + ci->password = decode(encoded_item); } if (ci->port[0] == '\0' || overwrite) @@ -869,10 +870,10 @@ getDSNinfo(ConnInfo *ci, char overwrite) } } - if (ci->conn_settings[0] == '\0' || overwrite) + if (NAME_IS_NULL(ci->conn_settings) || overwrite) { SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_item, sizeof(encoded_item), ODBC_INI); - decode(encoded_item, ci->conn_settings, sizeof(ci->conn_settings)); + ci->conn_settings = decode(encoded_item); } if (ci->translation_dll[0] == '\0' || overwrite) @@ -977,7 +978,7 @@ getDSNinfo(ConnInfo *ci, char overwrite) ci->port, ci->database, ci->username, - ci->password ? "xxxxx" : ""); + NAME_IS_VALID(ci->password) ? "xxxxx" : ""); qlog(" onlyread='%s',protocol='%s',showoid='%s',fakeoidindex='%s',showsystable='%s'\n", ci->onlyread, ci->protocol, @@ -1249,10 +1250,13 @@ writeDSNinfo(const ConnInfo *ci) void getCommonDefaults(const char *section, const char *filename, ConnInfo *ci) { + CSTR func = "getCommonDefaults"; char temp[256]; GLOBAL_VALUES *comval; BOOL inst_position = (stricmp(filename, ODBCINST_INI) == 0); + const char *drivername = (inst_position ? section : ci->drivername); + mylog("%s:setting %s position of %p\n", func, filename, ci); if (ci) comval = &(ci->drivers); else @@ -1415,18 +1419,22 @@ getCommonDefaults(const char *section, const char *filename, ConnInfo *ci) else if (inst_position) strcpy(comval->extra_systable_prefixes, DEFAULT_EXTRASYSTABLEPREFIXES); - mylog("globals.extra_systable_prefixes = '%s'\n", comval->extra_systable_prefixes); + mylog("ci=%p globals.extra_systable_prefixes = '%s'\n", ci, comval->extra_systable_prefixes); /* Dont allow override of an override! */ if (inst_position) { + char conn_settings[LARGE_REGISTRY_LEN]; + /* * ConnSettings is stored in the driver section and per datasource * for override */ SQLGetPrivateProfileString(section, INI_CONNSETTINGS, "", - comval->conn_settings, sizeof(comval->conn_settings), filename); + conn_settings, sizeof(conn_settings), filename); + if ('\0' != conn_settings[0]) + STR_TO_NAME(comval->conn_settings, conn_settings); /* Default state for future DSN's Readonly attribute */ SQLGetPrivateProfileString(section, INI_READONLY, "", @@ -1448,18 +1456,25 @@ getCommonDefaults(const char *section, const char *filename, ConnInfo *ci) else strcpy(comval->protocol, DEFAULT_PROTOCOL); } + STR_TO_NAME(comval->drivername, drivername); } static void -encode(const UCHAR *in, UCHAR *out, int outlen) +encode(const pgNAME in, UCHAR *out, int outlen) { - size_t i, ilen = strlen(in), - o = 0; - UCHAR inc; + size_t i, ilen, o = 0; + UCHAR inc, *ins; + if (NAME_IS_NULL(in)) + { + out[0] = '\0'; + return; + } + ins = GET_NAME(in); + ilen = strlen(ins); for (i = 0; i < ilen && o < outlen - 1; i++) { - inc = in[i]; + inc = ins[i]; if (inc == '+') { if (o + 2 >= outlen) @@ -1504,50 +1519,58 @@ conv_from_hex(const UCHAR *s) return y; } -static void -decode(const UCHAR *in, UCHAR *out, int outlen) +static pgNAME +decode(const UCHAR *in) { - size_t i, ilen = strlen(in), - o = 0; - UCHAR inc; + size_t i, ilen = strlen(in), o = 0; + UCHAR inc, *outs; + pgNAME out; - for (i = 0; i < ilen && o < outlen - 1; i++) + INIT_NAME(out); + if (0 == ilen) + { + return out; + } + outs = (char *) malloc(ilen + 1); + for (i = 0; i < ilen; i++) { inc = in[i]; if (inc == '+') - out[o++] = ' '; + outs[o++] = ' '; else if (inc == '%') { - sprintf(&out[o++], "%c", conv_from_hex(&in[i])); + sprintf(&outs[o++], "%c", conv_from_hex(&in[i])); i += 2; } else - out[o++] = inc; + outs[o++] = inc; } - out[o++] = '\0'; + outs[o++] = '\0'; + STR_TO_NAME(out, outs); + free(outs); + return out; } /* * Remove braces if the input value is enclosed by braces({}). * Othewise decode the input value. */ -static void -decode_or_remove_braces(const UCHAR *in, UCHAR *out, int outlen) +static pgNAME +decode_or_remove_braces(const UCHAR *in) { if ('{' == in[0]) { size_t inlen = strlen(in); if ('}' == in[inlen - 1]) /* enclosed by braces */ { - size_t limitlen = outlen; + pgNAME out; - if (inlen - 1 < limitlen) - limitlen = inlen - 1; - strncpy_null(out, in + 1, limitlen); - return; + INIT_NAME(out); + STRN_TO_NAME(out, in + 1, inlen - 2); + return out; } } - decode(in, out, outlen); + return decode(in); } char *extract_attribute_setting(const char *str, const char *attr, BOOL ref_comment) @@ -1677,9 +1700,9 @@ char *extract_attribute_setting(const char *str, const char *attr, BOOL ref_comm * extract the specified attribute from the comment part. * attribute=[']value['] */ -char *extract_extra_attribute_setting(const char *str, const char *attr) +char *extract_extra_attribute_setting(const pgNAME setting, const char *attr) { - const UCHAR *cptr, *sptr = NULL; + const UCHAR *cptr, *sptr = NULL, *str = GET_NAME(setting); UCHAR *rptr; BOOL allowed_cmd = FALSE, in_quote = FALSE, in_comment = FALSE; int step = 0, step_last = 2; diff --git a/dlg_specific.h b/dlg_specific.h index 0d00adf..addfe43 100644 --- a/dlg_specific.h +++ b/dlg_specific.h @@ -296,7 +296,7 @@ int changeDriverNameOfaDSN(const char *dsn, const char *driver_name, DWORD * UInt4 getExtraOptions(const ConnInfo *); BOOL setExtraOptions(ConnInfo *, const char *str, const char *format); char *extract_attribute_setting(const char *str, const char *attr, BOOL ref_comment); -char *extract_extra_attribute_setting(const char *str, const char *attr); +char *extract_extra_attribute_setting(const pgNAME setting, const char *attr); #ifdef __cplusplus } diff --git a/dlg_wingui.c b/dlg_wingui.c index 360f73d..77e86dc 100644 --- a/dlg_wingui.c +++ b/dlg_wingui.c @@ -63,7 +63,7 @@ SetDlgStuff(HWND hdlg, const ConnInfo *ci) SetDlgItemText(hdlg, IDC_DATABASE, ci->database); SetDlgItemText(hdlg, IDC_SERVER, ci->server); SetDlgItemText(hdlg, IDC_USER, ci->username); - SetDlgItemText(hdlg, IDC_PASSWORD, ci->password); + SetDlgItemText(hdlg, IDC_PASSWORD, SAFE_NAME(ci->password)); SetDlgItemText(hdlg, IDC_PORT, ci->port); dsplevel = 0; @@ -114,13 +114,15 @@ void GetDlgStuff(HWND hdlg, ConnInfo *ci) { int sslposition; + char medium_buf[MEDIUM_REGISTRY_LEN]; GetDlgItemText(hdlg, IDC_DESC, ci->desc, sizeof(ci->desc)); GetDlgItemText(hdlg, IDC_DATABASE, ci->database, sizeof(ci->database)); GetDlgItemText(hdlg, IDC_SERVER, ci->server, sizeof(ci->server)); GetDlgItemText(hdlg, IDC_USER, ci->username, sizeof(ci->username)); - GetDlgItemText(hdlg, IDC_PASSWORD, ci->password, sizeof(ci->password)); + GetDlgItemText(hdlg, IDC_PASSWORD, medium_buf, sizeof(medium_buf)); + STR_TO_NAME(ci->password, medium_buf); GetDlgItemText(hdlg, IDC_PORT, ci->port, sizeof(ci->port)); sslposition = (int)(DWORD)SendMessage(GetDlgItem(hdlg, IDC_SSLMODE), CB_GETCURSEL, 0L, 0L); strncpy_null(ci->sslmode, modetab[sslposition].modestr, sizeof(ci->sslmode)); @@ -214,7 +216,7 @@ driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable) SetDlgItemText(hdlg, DRV_EXTRASYSTABLEPREFIXES, comval->extra_systable_prefixes); /* Driver Connection Settings */ - SetDlgItemText(hdlg, DRV_CONNSETTINGS, comval->conn_settings); + SetDlgItemText(hdlg, DRV_CONNSETTINGS, SAFE_NAME(comval->conn_settings)); EnableWindow(GetDlgItem(hdlg, DRV_CONNSETTINGS), enable); ShowWindow(GetDlgItem(hdlg, IDPREVPAGE), enable ? SW_HIDE : SW_SHOW); ShowWindow(GetDlgItem(hdlg, IDNEXTPAGE), enable ? SW_HIDE : SW_SHOW); @@ -268,7 +270,13 @@ driver_options_update(HWND hdlg, ConnInfo *ci, const char *updateDriver) /* Driver Connection Settings */ if (!ci) - GetDlgItemText(hdlg, DRV_CONNSETTINGS, comval->conn_settings, sizeof(comval->conn_settings)); + { + char conn_settings[LARGE_REGISTRY_LEN]; + + GetDlgItemText(hdlg, DRV_CONNSETTINGS, conn_settings, sizeof(conn_settings)); + if ('\0' != conn_settings[0]) + STR_TO_NAME(comval->conn_settings, conn_settings); + } if (updateDriver) { @@ -595,7 +603,7 @@ ds_options2Proc(HWND hdlg, EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column)); /* Datasource Connection Settings */ - SetDlgItemText(hdlg, DS_CONNSETTINGS, ci->conn_settings); + SetDlgItemText(hdlg, DS_CONNSETTINGS, SAFE_NAME(ci->conn_settings)); break; case WM_COMMAND: @@ -670,7 +678,12 @@ ds_options2Proc(HWND hdlg, sprintf(ci->show_oid_column, "%d", IsDlgButtonChecked(hdlg, DS_SHOWOIDCOLUMN)); /* Datasource Connection Settings */ - GetDlgItemText(hdlg, DS_CONNSETTINGS, ci->conn_settings, sizeof(ci->conn_settings)); + { + char conn_settings[LARGE_REGISTRY_LEN]; + GetDlgItemText(hdlg, DS_CONNSETTINGS, conn_settings, sizeof(conn_settings)); + if ('\0' != conn_settings[0]) + STR_TO_NAME(ci->conn_settings, conn_settings); + } if (IDAPPLY == cmd) { SendMessage(GetWindow(hdlg, GW_OWNER), WM_COMMAND, wParam, lParam); diff --git a/drvconn.c b/drvconn.c index cf8a582..063aa3f 100644 --- a/drvconn.c +++ b/drvconn.c @@ -538,7 +538,7 @@ void dconn_get_connect_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci) { - CC_conninfo_init(ci); + CC_conninfo_init(ci, COPY_GLOBALS); dconn_get_attributes(copyAttributes, connect_string, ci); } diff --git a/multibyte.c b/multibyte.c index 5f65b63..61fe8c2 100644 --- a/multibyte.c +++ b/multibyte.c @@ -107,7 +107,7 @@ pg_CS_code(const UCHAR *characterset_string) return (c); } -UCHAR *check_client_encoding(const UCHAR *conn_settings) +UCHAR *check_client_encoding(const pgNAME conn_settings) { const UCHAR *cptr, *sptr = NULL; UCHAR *rptr; @@ -115,8 +115,10 @@ UCHAR *check_client_encoding(const UCHAR *conn_settings) int step = 0; size_t len = 0; - for (cptr = conn_settings; *cptr; cptr++) - { + if (NAME_IS_NULL(conn_settings)) + return NULL; + for (cptr = SAFE_NAME(conn_settings); *cptr; cptr++) + { if (in_quote) if (LITERAL_QUOTE == *cptr) { diff --git a/multibyte.h b/multibyte.h index 937d5bf..bba3c59 100644 --- a/multibyte.h +++ b/multibyte.h @@ -99,6 +99,7 @@ void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str); extern int encoded_nextchar(encoded_str *encstr); extern ssize_t encoded_position_shift(encoded_str *encstr, size_t shift); extern int encoded_byte_check(encoded_str *encstr, size_t abspos); -/* #define check_client_encoding(X) pg_CS_name(pg_CS_code(X)) */ -UCHAR *check_client_encoding(const UCHAR *sql_string); +/* #define check_client_encoding(X) pg_CS_name(pg_CS_code(X)) +UCHAR *check_client_encoding(const UCHAR *sql_string); */ +UCHAR *check_client_encoding(const pgNAME sql_string); #endif /* __MULTIBUYTE_H__ */ diff --git a/psqlodbc.c b/psqlodbc.c index 6ac3df4..ac5c57d 100644 --- a/psqlodbc.c +++ b/psqlodbc.c @@ -86,16 +86,33 @@ int initialize_global_cs(void) getMutexAttr(); #endif /* POSIX_THREADMUTEX_SUPPORT */ InitializeLogging(); + memset(&globals, 0, sizeof(globals)); INIT_CONNS_CS; INIT_COMMON_CS; return 0; } +void copy_globals(GLOBAL_VALUES *to, const GLOBAL_VALUES *from) +{ + memcpy(to, from, sizeof(GLOBAL_VALUES)); + SET_NAME_DIRECTLY(to->drivername, NULL); + SET_NAME_DIRECTLY(to->conn_settings, NULL); + NAME_TO_NAME(to->drivername, from->drivername); + NAME_TO_NAME(to->conn_settings, from->conn_settings); +mylog("copy_globals driver=%s socket_buffersize=%d\n", SAFE_NAME(to->drivername), to->socket_buffersize); +} +void finalize_globals(GLOBAL_VALUES *glbv) +{ + NULL_THE_NAME(glbv->drivername); + NULL_THE_NAME(glbv->conn_settings); +} + static void finalize_global_cs(void) { DELETE_COMMON_CS; DELETE_CONNS_CS; + finalize_globals(&globals); FinalizeLogging(); #ifdef _DEBUG #ifdef _MEMORY_DEBUG_ diff --git a/psqlodbc.h b/psqlodbc.h index 51d70a3..f9aa5a8 100644 --- a/psqlodbc.h +++ b/psqlodbc.h @@ -159,7 +159,7 @@ typedef unsigned long long ULONG_PTR; #define FORMAT_LEN "%ld" /* SQLLEN */ #define FORMAT_ULEN "%lu" /* SQLULEN */ #define FORMAT_INTEGER "%ld" /* SQLINTEGER */ -#define FORMAT_UINTEGER "%lu" /* SQLUINTEGER */ +#define FORMAT_UINTEGER "%u" /* SQLUINTEGER */ #endif /* SIZEOF_VOID_P */ #endif /* WIN32 */ #define CAST_PTR(type, ptr) (type)((LONG_PTR)(ptr)) @@ -234,7 +234,9 @@ typedef double SDOUBLE; #endif /* DBMS_NAME */ #else #define DRIVER_ODBC_VER "02.50" +#ifndef DBMS_NAME #define DBMS_NAME "PostgreSQL Legacy" +#endif /* DBMS_NAME */ #endif /* ODBCVER */ #ifdef WIN32 @@ -379,8 +381,78 @@ typedef struct IPDFields_ IPDFields; typedef struct col_info COL_INFO; typedef struct lo_arg LO_ARG; + +/* pgNAME type define */ +typedef struct +{ + char *name; +} pgNAME; +#define GET_NAME(the_name) ((the_name).name) +#define SAFE_NAME(the_name) ((the_name).name ? (the_name).name : NULL_STRING) +#define PRINT_NAME(the_name) ((the_name).name ? (the_name).name : PRINT_NULL) +#define NAME_IS_NULL(the_name) (NULL == (the_name).name) +#define NAME_IS_VALID(the_name) (NULL != (the_name).name) +#define INIT_NAME(the_name) ((the_name).name = NULL) +#define NULL_THE_NAME(the_name) \ +do { \ + if ((the_name).name) free((the_name).name); \ + (the_name).name = NULL; \ +} while (0) +#define STR_TO_NAME(the_name, str) \ +do { \ + if ((the_name).name) \ + free((the_name).name); \ + (the_name).name = (str ? strdup((str)) : NULL); \ +} while (0) +#define STRX_TO_NAME(the_name, str) \ +do { \ + if ((the_name).name) \ + free((the_name).name); \ + (the_name).name = strdup((str)); \ +} while (0) +#define STRN_TO_NAME(the_name, str, n) \ +do { \ + if ((the_name).name) \ + free((the_name).name); \ + if (str) \ + { \ + (the_name).name = malloc((n) + 1); \ + memcpy((the_name).name, str, (n)); \ + (the_name).name[(n)] = '\0'; \ + } \ + else \ + (the_name).name = NULL; \ +} while (0) +#define NAME_TO_STR(str, the_name) \ +do {\ + if ((the_name).name) strcpy(str, (the_name).name); \ + else *str = '\0'; \ +} while (0) +#define NAME_TO_NAME(to, from) \ +do { \ + if ((to).name) \ + free((to).name); \ + if ((from).name) \ + (to).name = strdup(from.name); \ + else \ + (to).name = NULL; \ +} while (0) +#define MOVE_NAME(to, from) \ +do { \ + if ((to).name) \ + free((to).name); \ + (to).name = (from).name; \ + (from).name = NULL; \ +} while (0) +#define SET_NAME_DIRECTLY(the_name, str) ((the_name).name = (str)) + +#define NAMECMP(name1, name2) (strcmp(SAFE_NAME(name1), SAFE_NAME(name2))) +#define NAMEICMP(name1, name2) (stricmp(SAFE_NAME(name1), SAFE_NAME(name2))) +/* pgNAME define end */ + typedef struct GlobalValues_ { + pgNAME drivername; int fetch_max; int socket_buffersize; int unknown_sizes; @@ -401,10 +473,13 @@ typedef struct GlobalValues_ char parse; char cancel_as_freestmt; char extra_systable_prefixes[MEDIUM_REGISTRY_LEN]; - char conn_settings[LARGE_REGISTRY_LEN]; char protocol[SMALL_REGISTRY_LEN]; + pgNAME conn_settings; } GLOBAL_VALUES; +void copy_globals(GLOBAL_VALUES *to, const GLOBAL_VALUES *from); +void finalize_globals(GLOBAL_VALUES *glbv); + typedef struct StatementOptions_ { SQLLEN maxRows; diff --git a/results.c b/results.c index 21dfc35..5c88c6b 100644 --- a/results.c +++ b/results.c @@ -4529,7 +4529,7 @@ PGAPI_SetCursorName( return SQL_INVALID_HANDLE; } - SET_NAME(stmt->cursor_name, make_string(szCursor, cbCursor, NULL, 0)); + SET_NAME_DIRECTLY(stmt->cursor_name, make_string(szCursor, cbCursor, NULL, 0)); return SQL_SUCCESS; } diff --git a/setup.c b/setup.c index ab48f9c..6c9cd85 100644 --- a/setup.c +++ b/setup.c @@ -275,7 +275,7 @@ ConfigDlgProc(HWND hdlg, */ /* override settings in ODBC.INI */ - memcpy(&ci->drivers, &globals, sizeof(globals)); + copy_globals(&ci->drivers, &globals); /* Get the rest of the common attributes */ getDSNinfo(ci, CONN_DONT_OVERWRITE); @@ -367,7 +367,7 @@ ConfigDlgProc(HWND hdlg, int errnum; EN_add_connection(env, conn); - memcpy(&conn->connInfo, &lpsetupdlg->ci, sizeof(ConnInfo)); + CC_copy_conninfo(&conn->connInfo, &lpsetupdlg->ci); CC_initialize_pg_version(conn); logs_on_off(1, conn->connInfo.drivers.debug, conn->connInfo.drivers.commlog); #ifdef UNICODE_SUPPORT @@ -469,7 +469,7 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg) int cbKey; char value[MAXPGPATH]; - CC_conninfo_init(&(lpsetupdlg->ci)); + CC_conninfo_init(&(lpsetupdlg->ci), COPY_GLOBALS); for (lpsz = lpszAttributes; *lpsz; lpsz++) { -- 2.39.5