From 454cb1a285c84220171fd0ff141595a0030d369f Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Sun, 18 Jan 2009 13:09:55 +0000 Subject: [PATCH] 1) Fix a bug reported by Milen Manev that SQLExec *select for a table* -> SQLDescribeCol() -> add a column to the table -> SQLExec *select for the table* -> SQLDescribeCol() for the added column causes a bad result. 2) Use strncpy_null() instead of strncpy(). --- connection.c | 30 +++--- connection.h | 7 ++ convert.c | 2 +- dlg_specific.c | 4 +- dlg_wingui.c | 8 +- environ.c | 2 +- info.c | 24 ++--- parse.c | 287 +++++++++++++++++++++++++++++-------------------- pgtypes.c | 16 ++- pgtypes.h | 1 + results.c | 13 ++- setup.c | 2 +- socket.c | 4 +- statement.c | 7 +- version.h | 2 +- 15 files changed, 245 insertions(+), 164 deletions(-) diff --git a/connection.c b/connection.c index baed5cb..88dc095 100644 --- a/connection.c +++ b/connection.c @@ -780,7 +780,7 @@ handle_error_message(ConnectionClass *self, char *msgbuf, size_t buflen, char *s mylog("peek the next byte = \\0\n"); new_format = TRUE; - strncpy(ci->protocol, PG74, sizeof(ci->protocol)); + strncpy_null(ci->protocol, PG74, sizeof(ci->protocol)); leng = SOCK_get_response_length(sock); inolog("get the response length=%d\n", leng); } @@ -833,7 +833,7 @@ inolog("new_format=%d\n", new_format); break; case 'C': if (sqlstate) - strncpy(sqlstate, msgbuffer + 1, 8); + strncpy_null(sqlstate, msgbuffer + 1, 8); break; } if (buflen < 0) @@ -944,7 +944,7 @@ handle_notice_message(ConnectionClass *self, char *msgbuf, size_t buflen, char * break; case 'C': if (sqlstate && !sqlstate[0] && strcmp(msgbuffer + 1, "00000")) - strncpy(sqlstate, msgbuffer + 1, 8); + strncpy_null(sqlstate, msgbuffer + 1, 8); break; } if (buflen < 0) @@ -1015,7 +1015,7 @@ inolog("parameter name=%s\n", msgbuffer); int major, minor; SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer)); - strncpy(conn->pg_version, msgbuffer, sizeof(conn->pg_version)); + strncpy_null(conn->pg_version, msgbuffer, sizeof(conn->pg_version)); strcpy(szVersion, "0.0"); if (sscanf(conn->pg_version, "%d.%d", &major, &minor) >= 2) { @@ -1407,11 +1407,11 @@ another_version_retry: return 0; } if (PROTOCOL_63(ci)) - strncpy(ci->protocol, PG62, sizeof(ci->protocol)); + strncpy_null(ci->protocol, PG62, sizeof(ci->protocol)); else if (PROTOCOL_64(ci)) - strncpy(ci->protocol, PG63, sizeof(ci->protocol)); + strncpy_null(ci->protocol, PG63, sizeof(ci->protocol)); else - strncpy(ci->protocol, PG64, sizeof(ci->protocol)); + strncpy_null(ci->protocol, PG64, sizeof(ci->protocol)); #ifdef USE_SSPI ssl_try_no = 0; } @@ -1508,8 +1508,8 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self sock->pversion = PG_PROTOCOL_62; SOCK_put_int(sock, htonl(4 + sizeof(StartupPacket6_2)), 4); sp62.authtype = htonl(NO_AUTHENTICATION); - strncpy(sp62.database, ci->database, PATH_SIZE); - strncpy(sp62.user, ci->username, USRNAMEDATALEN); + strncpy_null(sp62.database, ci->database, PATH_SIZE); + strncpy_null(sp62.user, ci->username, USRNAMEDATALEN); SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2)); SOCK_flush_output(sock); } @@ -1533,8 +1533,8 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self sp.protoVersion = (ProtocolVersion) htonl(sock->pversion); - strncpy(sp.database, ci->database, SM_DATABASE); - strncpy(sp.user, ci->username, SM_USER); + strncpy_null(sp.database, ci->database, SM_DATABASE); + strncpy_null(sp.user, ci->username, SM_USER); SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket)); SOCK_flush_output(sock); @@ -1585,7 +1585,7 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self goto sockerr_proc; } else - strncpy(ci->protocol, PG74REJECTED, sizeof(ci->protocol)); + strncpy_null(ci->protocol, PG74REJECTED, sizeof(ci->protocol)); } startPacketReceived = TRUE; } @@ -2051,7 +2051,7 @@ CC_create_errormsg(ConnectionClass *self) msg[0] = '\0'; if (CC_get_errormsg(self)) - strncpy(msg, CC_get_errormsg(self), sizeof(msg)); + strncpy_null(msg, CC_get_errormsg(self), sizeof(msg)); mylog("msg = '%s'\n", msg); @@ -3664,13 +3664,13 @@ if (TRUE) ConnInfo *ci = &self->connInfo; sock->pversion = PG_PROTOCOL_74; - strncpy(ci->protocol, PG74, sizeof(ci->protocol)); + strncpy_null(ci->protocol, PG74, sizeof(ci->protocol)); pversion = PQprotocolVersion(pqconn); switch (pversion) { case 2: sock->pversion = PG_PROTOCOL_64; - strncpy(ci->protocol, PG64, sizeof(ci->protocol)); + strncpy_null(ci->protocol, PG64, sizeof(ci->protocol)); break; } } diff --git a/connection.h b/connection.h index 0185000..c500c04 100644 --- a/connection.h +++ b/connection.h @@ -376,6 +376,13 @@ struct col_info pgNAME table_name; OID table_oid; }; +#define free_col_info_contents(coli) \ +{ \ + if (NULL != coli->result) \ + QR_Destructor(coli->result); \ + NULL_THE_NAME(coli->schema_name); \ + NULL_THE_NAME(coli->table_name); \ +} #define col_info_initialize(coli) (memset(coli, 0, sizeof(COL_INFO))) /* Translation DLL entry points */ diff --git a/convert.c b/convert.c index 7de1fdd..42ba628 100644 --- a/convert.c +++ b/convert.c @@ -1072,7 +1072,7 @@ inolog("2stime fr=%d\n", std_time.fr); for (i = 0, j = 0; ptr[i]; i++) if (ptr[i] == '.') { - strncpy(&new_string[j], lc->decimal_point, strlen(lc->decimal_point)); + strncpy_null(&new_string[j], lc->decimal_point, strlen(lc->decimal_point)); j += strlen(lc->decimal_point); } else diff --git a/dlg_specific.c b/dlg_specific.c index 2d18913..5103577 100644 --- a/dlg_specific.c +++ b/dlg_specific.c @@ -169,7 +169,7 @@ inolog("hlen=%d", hlen); if (ci->rollback_on_error >= 0) snprintf(protocol_and, sizeof(protocol_and), "%s-%d", ci->protocol, ci->rollback_on_error); else - strncpy(protocol_and, ci->protocol, sizeof(protocol_and)); + strncpy_null(protocol_and, ci->protocol, sizeof(protocol_and)); olen = snprintf(&connect_string[hlen], nlen, ";" INI_SSLMODE "=%s;" INI_READONLY "=%s;" @@ -1072,7 +1072,7 @@ writeDSNinfo(const ConnInfo *ci) if (ci->rollback_on_error >= 0) sprintf(temp, "%s-%d", ci->protocol, ci->rollback_on_error); else - strncpy(temp, ci->protocol, sizeof(temp)); + strncpy_null(temp, ci->protocol, sizeof(temp)); SQLWritePrivateProfileString(DSN, INI_PROTOCOL, temp, diff --git a/dlg_wingui.c b/dlg_wingui.c index f9a3ced..178af08 100644 --- a/dlg_wingui.c +++ b/dlg_wingui.c @@ -100,13 +100,13 @@ GetDlgStuff(HWND hdlg, ConnInfo *ci) sslposition = (int)(DWORD)SendMessage(GetDlgItem(hdlg, IDC_SSLMODE), CB_GETCURSEL, 0L, 0L); switch (sslposition) { - case 1: strncpy(ci->sslmode, "prefer", sizeof(ci->sslmode)); + case 1: strncpy_null(ci->sslmode, "prefer", sizeof(ci->sslmode)); break; - case 2: strncpy(ci->sslmode, "allow", sizeof(ci->sslmode)); + case 2: strncpy_null(ci->sslmode, "allow", sizeof(ci->sslmode)); break; - case 3: strncpy(ci->sslmode, "require", sizeof(ci->sslmode)); + case 3: strncpy_null(ci->sslmode, "require", sizeof(ci->sslmode)); break; - default:strncpy(ci->sslmode, "disable", sizeof(ci->sslmode)); + default:strncpy_null(ci->sslmode, "disable", sizeof(ci->sslmode)); break; } } diff --git a/environ.c b/environ.c index b764bb5..09302e5 100644 --- a/environ.c +++ b/environ.c @@ -245,7 +245,7 @@ ER_ReturnError(PG_ErrorInfo **pgerror, *pfNativeError = error->status; if (NULL != szSqlState) - strncpy(szSqlState, error->sqlstate, 6); + strncpy_null(szSqlState, error->sqlstate, 6); mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg); if (clear_str) diff --git a/info.c b/info.c index 7681bc3..2a32dd9 100644 --- a/info.c +++ b/info.c @@ -1620,16 +1620,16 @@ retry_public_schema: tables_query[0] = '\0'; if (list_cat) - strncpy(tables_query, "select NULL, NULL, NULL", sizeof(tables_query)); + strncpy_null(tables_query, "select NULL, NULL, NULL", sizeof(tables_query)); else if (list_table_types) - strncpy(tables_query, "select NULL, NULL, relkind from (select 'r' as relkind union select 'v') as a", sizeof(tables_query)); + strncpy_null(tables_query, "select NULL, NULL, relkind from (select 'r' as relkind union select 'v') as a", sizeof(tables_query)); else if (list_schemas) { if (conn->schema_support) - strncpy(tables_query, "select NULL, nspname, NULL" + strncpy_null(tables_query, "select NULL, nspname, NULL" " from pg_catalog.pg_namespace n where true", sizeof(tables_query)); else - strncpy(tables_query, "select NULL, NULL as nspname, NULL", sizeof(tables_query)); + strncpy_null(tables_query, "select NULL, NULL as nspname, NULL", sizeof(tables_query)); } else if (conn->schema_support) { @@ -2420,12 +2420,8 @@ mylog(" and the data=%s\n", attdef); set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name); set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], field_name); auto_unique = SQL_FALSE; - if (basetype != 0 && - field_type != conn->lobj_type) - { - field_type = basetype; + if (field_type = pg_true_type(conn, field_type, basetype), field_type == basetype) mod_length = typmod; - } switch (field_type) { case PG_TYPE_INT4: @@ -3697,7 +3693,7 @@ retry_public_schema: */ if (conn->schema_support) { - strncpy(tables_query, + strncpy_null(tables_query, "select ta.attname, ia.attnum, ic.relname, n.nspname, tc.relname" " from pg_catalog.pg_attribute ta," " pg_catalog.pg_attribute ia, pg_catalog.pg_class tc," @@ -3732,7 +3728,7 @@ retry_public_schema: } else { - strncpy(tables_query, + strncpy_null(tables_query, "select ta.attname, ia.attnum, ic.relname, NULL, tc.relname" " from pg_attribute ta, pg_attribute ia, pg_class tc, pg_index i, pg_class ic" , sizeof(tables_query)); @@ -4455,7 +4451,7 @@ PGAPI_ForeignKeys_old( set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text); mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text); - set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]); + set_tuplefield_string(&tuple[FKS_FKTABLE_CAT], CurrCat(conn)); set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed)); set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_needed); set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text); @@ -4782,7 +4778,7 @@ PGAPI_ForeignKeys_old( set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text); mylog("fk_table = '%s', fkey_ptr = '%s'\n", fk_table_fetched, fkey_text); - set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]); + set_tuplefield_string(&tuple[FKS_FKTABLE_CAT], CurrCat(conn)); set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched)); set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_fetched); set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text); @@ -4881,7 +4877,7 @@ PGAPI_ForeignKeys( SQLSMALLINT cbFkTableName) { ConnectionClass *conn = SC_get_conn(((StatementClass *) hstmt)); - if (PG_VERSION_GE(conn, 8.3)) + if (PG_VERSION_GE(conn, 8.1)) return PGAPI_ForeignKeys_new(hstmt, szPkTableQualifier, cbPkTableQualifier, szPkTableOwner, cbPkTableOwner, diff --git a/parse.c b/parse.c index f6be8ca..2cedf37 100644 --- a/parse.c +++ b/parse.c @@ -44,6 +44,7 @@ static char *getNextToken(int ccsc, char escape_in_literal, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric); static void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k); static char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi); +static BOOL getColumnsInfo(ConnectionClass *, TABLE_INFO *, OID, StatementClass *); Int4 FI_precision(const FIELD_INFO *fi) { @@ -513,7 +514,10 @@ static BOOL allocateFields(IRDFields *irdflds, size_t sizeRequested) return TRUE; } -static void xxxxx(FIELD_INFO *fi, QResultClass *res, int i) +/* + * This function may not be called but when it is called ... + */ +static void xxxxx(StatementClass *stmt, FIELD_INFO *fi, QResultClass *res, int i) { STR_TO_NAME(fi->column_alias, QR_get_fieldname(res, i)); fi->basetype = QR_get_field_type(res, i); @@ -525,7 +529,16 @@ static void xxxxx(FIELD_INFO *fi, QResultClass *res, int i) fi->updatable = FALSE; } else if (fi->attnum > 0) + { + int unknowns_as = 0; + int type = pg_true_type(SC_get_conn(stmt), fi->columntype, fi->basetype); + fi->nullable = TRUE; /* probably ? */ + fi->column_size = pgtype_column_size(stmt, type, i, unknowns_as); + fi->length = pgtype_buffer_length(stmt, type, i, unknowns_as); + fi->decimal_digits = pgtype_decimal_digits(stmt, type, i); + fi->display_size = pgtype_display_size(stmt, type, i, unknowns_as); + } if (NAME_IS_NULL(fi->column_name)) { @@ -590,7 +603,7 @@ static BOOL ColAttSet(StatementClass *stmt, TABLE_INFO *rti) OID reloid = 0; Int2 attid; int i, num_fields; - BOOL fi_reuse, updatable; + BOOL fi_reuse, updatable, call_xxxxx; mylog("ColAttSet in\n"); if (rti) @@ -640,16 +653,30 @@ mylog("->%d\n", updatable); FI_Constructor(wfi, fi_reuse); attid = (Int2) QR_get_attid(res, i); wfi->attnum = attid; + call_xxxxx = TRUE; if (searchColInfo(col_info, wfi)) { STR_TO_NAME(wfi->column_alias, QR_get_fieldname(res, i)); wfi->basetype = QR_get_field_type(res, i); wfi->updatable = updatable; + call_xxxxx = FALSE; } else { - xxxxx(wfi, res, i); + if (attid > 0) + { + if (getColumnsInfo(NULL, rti, reloid, stmt) && + searchColInfo(col_info, wfi)) + { + STR_TO_NAME(wfi->column_alias, QR_get_fieldname(res, i)); + wfi->basetype = QR_get_field_type(res, i); + wfi->updatable = updatable; + call_xxxxx= FALSE; + } + } } + if (call_xxxxx) + xxxxx(stmt, wfi, res, i); wfi->ti = rti; wfi->flag |= FIELD_COL_ATTRIBUTE; } @@ -746,14 +773,154 @@ COL_INFO **coli) return TRUE; /* success */ } +static BOOL +getColumnsInfo(ConnectionClass *conn, TABLE_INFO *wti, OID greloid, StatementClass *stmt) +{ + BOOL found = FALSE; + RETCODE result; + HSTMT hcol_stmt = NULL; + StatementClass *col_stmt; + QResultClass *res; + + mylog("PARSE: Getting PG_Columns for table %u(%s)\n", greloid, PRINT_NAME(wti->table_name)); + + if (NULL == conn) + conn = SC_get_conn(stmt); + result = PGAPI_AllocStmt(conn, &hcol_stmt); + if (!SQL_SUCCEEDED(result)) + { + if (stmt) + SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", __FUNCTION__); + goto cleanup; + } + + col_stmt = (StatementClass *) hcol_stmt; + col_stmt->internal = TRUE; + + if (greloid) + result = PGAPI_Columns(hcol_stmt, NULL, 0, + NULL, 0, NULL, 0, NULL, 0, + PODBC_SEARCH_BY_IDS, greloid, 0); + else + result = PGAPI_Columns(hcol_stmt, NULL, 0, SAFE_NAME(wti->schema_name), + SQL_NTS, SAFE_NAME(wti->table_name), SQL_NTS, NULL, 0, PODBC_NOT_SEARCH_PATTERN, 0, 0); + + mylog(" Past PG_Columns\n"); + res = SC_get_Curres(col_stmt); + if (SQL_SUCCEEDED(result) + && res != NULL && QR_get_num_cached_tuples(res) > 0) + { + BOOL coli_exist = FALSE; + COL_INFO *coli = NULL; + + mylog(" Success\n"); + if (greloid != 0) + { + int k; + + for (k = 0; k < conn->ntables; k++) + { + if (conn->col_info[k]->table_oid == greloid) + { + coli = conn->col_info[k]; + coli_exist = TRUE; + break; + } + } + } + if (coli_exist) + { + free_col_info_contents(coli); + } + else + { + if (conn->ntables >= conn->coli_allocated) + { + Int2 new_alloc; + + new_alloc = conn->coli_allocated * 2; + if (new_alloc <= conn->ntables) + new_alloc = COLI_INCR; + mylog("PARSE: Allocating col_info at ntables=%d\n", conn->ntables); + + conn->col_info = (COL_INFO **) realloc(conn->col_info, new_alloc * sizeof(COL_INFO *)); + if (!conn->col_info) + { + if (stmt) + SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", __FUNCTION__); + goto cleanup; + } + conn->coli_allocated = new_alloc; + } + + mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables); + coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO)); + } + if (!coli) + { + if (stmt) + SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", __FUNCTION__); + goto cleanup; + } + col_info_initialize(coli); + + coli->result = res; + if (res && QR_get_num_cached_tuples(res) > 0) + { + if (!greloid) + greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10); + if (!wti->table_oid) + wti->table_oid = greloid; + if (NAME_IS_NULL(wti->schema_name)) + STR_TO_NAME(wti->schema_name, + QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME)); + if (NAME_IS_NULL(wti->table_name)) + STR_TO_NAME(wti->table_name, + QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME)); + } +inolog("#2 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid); + /* + * Store the table name and the SQLColumns result + * structure + */ + if (NAME_IS_VALID(wti->schema_name)) + { + NAME_TO_NAME(coli->schema_name, wti->schema_name); + } + else + NULL_THE_NAME(coli->schema_name); + NAME_TO_NAME(coli->table_name, wti->table_name); + coli->table_oid = wti->table_oid; + + /* + * The connection will now free the result structures, so + * make sure that the statement doesn't free it + */ + SC_init_Result(col_stmt); + + if (!coli_exist) + conn->ntables++; + +if (res && QR_get_num_cached_tuples(res) > 0) +inolog("oid item == %s\n", QR_get_value_backend_text(res, 0, 3)); + + mylog("Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables); + /* Associate a table from the statement with a SQLColumn info */ + found = TRUE; + wti->col_info = coli; + } +cleanup: + if (hcol_stmt) + PGAPI_FreeStmt(hcol_stmt, SQL_DROP); + return found; +} + BOOL getCOLIfromTI(const char *func, ConnectionClass *conn, StatementClass *stmt, const OID reloid, TABLE_INFO **pti) { BOOL colatt = FALSE, found = FALSE; OID greloid = reloid; TABLE_INFO *wti = *pti; COL_INFO *coli; - HSTMT hcol_stmt = NULL; - QResultClass *res; inolog("getCOLIfromTI reloid=%u ti=%p\n", reloid, wti); if (!conn) @@ -826,116 +993,8 @@ inolog("fi=%p greloid=%d col_info=%p\n", wti, greloid, wti->col_info); if (found) goto cleanup; else if (0 != greloid || NAME_IS_VALID(wti->table_name)) - { - RETCODE result; - StatementClass *col_stmt; - - mylog("PARSE: Getting PG_Columns for table='%s'\n", wti->table_name); - - result = PGAPI_AllocStmt(conn, &hcol_stmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - if (stmt) - SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", func); - goto cleanup; - } - - col_stmt = (StatementClass *) hcol_stmt; - col_stmt->internal = TRUE; - - if (greloid) - result = PGAPI_Columns(hcol_stmt, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, - PODBC_SEARCH_BY_IDS, greloid, 0); - else - result = PGAPI_Columns(hcol_stmt, NULL, 0, SAFE_NAME(wti->schema_name), - SQL_NTS, SAFE_NAME(wti->table_name), SQL_NTS, NULL, 0, PODBC_NOT_SEARCH_PATTERN, 0, 0); - - mylog(" Past PG_Columns\n"); - res = SC_get_Curres(col_stmt); - if ((SQL_SUCCESS == result || SQL_SUCCESS_WITH_INFO == result) - && res && QR_get_num_cached_tuples(res) > 0) - { - COL_INFO *coli; - - mylog(" Success\n"); - if (conn->ntables >= conn->coli_allocated) - { - Int2 new_alloc; - - new_alloc = conn->coli_allocated * 2; - if (new_alloc <= conn->ntables) - new_alloc = COLI_INCR; - mylog("PARSE: Allocating col_info at ntables=%d\n", conn->ntables); - - conn->col_info = (COL_INFO **) realloc(conn->col_info, new_alloc * sizeof(COL_INFO *)); - if (!conn->col_info) - { - if (stmt) - SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", func); - goto cleanup; - } - conn->coli_allocated = new_alloc; - } - - mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables); - coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO)); - if (!coli) - { - if (stmt) - SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", func); - goto cleanup; - } - col_info_initialize(coli); - - coli->result = res; - if (res && QR_get_num_cached_tuples(res) > 0) - { - if (!greloid) - greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10); - if (!wti->table_oid) - wti->table_oid = greloid; - if (NAME_IS_NULL(wti->schema_name)) - STR_TO_NAME(wti->schema_name, - QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME)); - if (NAME_IS_NULL(wti->table_name)) - STR_TO_NAME(wti->table_name, - QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME)); - } -inolog("#2 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid); - /* - * Store the table name and the SQLColumns result - * structure - */ - if (NAME_IS_VALID(wti->schema_name)) - { - NAME_TO_NAME(coli->schema_name, wti->schema_name); - } - else - NULL_THE_NAME(coli->schema_name); - NAME_TO_NAME(coli->table_name, wti->table_name); - coli->table_oid = wti->table_oid; - - /* - * The connection will now free the result structures, so - * make sure that the statement doesn't free it - */ - SC_init_Result(col_stmt); - - conn->ntables++; - -if (res && QR_get_num_cached_tuples(res) > 0) -inolog("oid item == %s\n", QR_get_value_backend_text(res, 0, 3)); - - mylog("Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables); - /* Associate a table from the statement with a SQLColumn info */ - found = TRUE; - wti->col_info = coli; - } - } + found = getColumnsInfo(conn, wti, greloid, stmt); cleanup: - if (hcol_stmt) - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); if (found) { QResultClass *res = wti->col_info->result; diff --git a/pgtypes.c b/pgtypes.c index ddb2f53..298a162 100644 --- a/pgtypes.c +++ b/pgtypes.c @@ -120,6 +120,18 @@ SQLSMALLINT sqlTypes[] = { #define ALLOWED_C_BIGINT SQL_C_CHAR #endif +OID +pg_true_type(const ConnectionClass *conn, OID type, OID basetype) +{ + if (0 == basetype) + return type; + else if (0 == type) + return basetype; + else if (type == conn->lobj_type) + return type; + return basetype; +} + OID sqltype_to_pgtype(StatementClass *stmt, SQLSMALLINT fSqlType) { @@ -258,7 +270,7 @@ pgtype_to_concise_type(StatementClass *stmt, OID type, int col) ConnectionClass *conn = SC_get_conn(stmt); ConnInfo *ci = &(conn->connInfo); #if (ODBCVER >= 0x0300) - EnvironmentClass *env = (EnvironmentClass *) (conn->henv); + EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); #endif /* ODBCVER */ switch (type) @@ -437,7 +449,7 @@ pgtype_to_ctype(StatementClass *stmt, OID type) ConnectionClass *conn = SC_get_conn(stmt); ConnInfo *ci = &(conn->connInfo); #if (ODBCVER >= 0x0300) - EnvironmentClass *env = (EnvironmentClass *) (conn->henv); + EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); #endif /* ODBCVER */ switch (type) diff --git a/pgtypes.h b/pgtypes.h index ba94999..421c152 100644 --- a/pgtypes.h +++ b/pgtypes.h @@ -83,6 +83,7 @@ extern SQLSMALLINT sqlTypes[]; /* Defines for pgtype_precision */ #define PG_STATIC (-1) +OID pg_true_type(const ConnectionClass *, OID, OID); OID sqltype_to_pgtype(StatementClass *stmt, SQLSMALLINT fSqlType); SQLSMALLINT pgtype_to_concise_type(StatementClass *stmt, OID type, int col); diff --git a/results.c b/results.c index f7ba1e0..d878f06 100644 --- a/results.c +++ b/results.c @@ -339,7 +339,7 @@ inolog("answering bookmark info\n"); } if (FI_is_applicable(fi)) { - fieldtype = (conn->lobj_type == fi->columntype) ? fi->columntype : FI_type(fi); + fieldtype = pg_true_type(conn, fi->columntype, FI_type(fi)); if (NAME_IS_VALID(fi->column_alias)) col_name = GET_NAME(fi->column_alias); else @@ -466,6 +466,7 @@ PGAPI_ColAttributes( const FIELD_INFO *fi = NULL; const TABLE_INFO *ti = NULL; QResultClass *res; + BOOL stmt_updatable; mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType, cbDescMax); @@ -475,6 +476,7 @@ PGAPI_ColAttributes( SC_log_error(func, NULL_STRING, NULL); return SQL_INVALID_HANDLE; } + stmt_updatable = stmt->updatable && stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY; if (pcbDesc) *pcbDesc = 0; @@ -555,7 +557,7 @@ inolog("answering bookmark info\n"); if (col_idx < irdflds->nfields && irdflds->fi) fi = irdflds->fi[col_idx]; if (FI_is_applicable(fi)) - field_type = (conn->lobj_type == fi->columntype) ? fi->columntype : FI_type(fi); + field_type = pg_true_type(conn, fi->columntype, FI_type(fi)); else { BOOL build_fi = FALSE; @@ -618,7 +620,7 @@ inolog("answering bookmark info\n"); if (FI_is_applicable(fi)) { ti = fi->ti; - field_type = (conn->lobj_type == fi->columntype) ? fi->columntype : FI_type(fi); + field_type = pg_true_type(conn, fi->columntype, FI_type(fi)); } mylog("colAttr: col %d field_type=%d fi,ti=%p,%p\n", col_idx, field_type, fi, ti); @@ -760,7 +762,10 @@ inolog("COLUMN_SCALE=%d\n", value); * if (field_type == PG_TYPE_OID) pfDesc = SQL_ATTR_READONLY; * else */ - value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : (QR_get_attid(res, col_idx) > 0 ? SQL_ATTR_WRITE : (PROTOCOL_74(ci) ? SQL_ATTR_READONLY : SQL_ATTR_READWRITE_UNKNOWN)); + if (!stmt_updatable) + value = SQL_ATTR_READONLY; + else + value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : (QR_get_attid(res, col_idx) > 0 ? SQL_ATTR_WRITE : (PROTOCOL_74(ci) ? SQL_ATTR_READONLY : SQL_ATTR_READWRITE_UNKNOWN)); if (SQL_ATTR_READONLY != value) { const char *name = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(res, col_idx); diff --git a/setup.c b/setup.c index f8d6e35..a91b9be 100644 --- a/setup.c +++ b/setup.c @@ -316,7 +316,7 @@ ConfigDlgProc(HWND hdlg, snprintf(szMsg, sizeof(szMsg), "Warning: %s", emsg); } else - strncpy(szMsg, "Connection successful", sizeof(szMsg)); + strncpy_null(szMsg, "Connection successful", sizeof(szMsg)); emsg = szMsg; } else diff --git a/socket.c b/socket.c index aeec5cd..d131d48 100644 --- a/socket.c +++ b/socket.c @@ -203,7 +203,7 @@ static BOOL format_sockerr(char *errmsg, size_t buflen, int errnum, const char * if (NULL != pchar) { if (pchar != errmsg) - strncpy(errmsg, pchar, buflen); + strncpy_null(errmsg, pchar, buflen); ret = TRUE; } #else @@ -211,7 +211,7 @@ static BOOL format_sockerr(char *errmsg, size_t buflen, int errnum, const char * ret = TRUE; #endif /* STRERROR_R_CHAR_P */ #else - strncpy(errmsg, strerror(errnum), buflen); + strncpy_null(errmsg, strerror(errnum), buflen); ret = TRUE; #endif /* POSIX_MULTITHREAD_SUPPORT */ #endif /* WIN32 */ diff --git a/statement.c b/statement.c index 21f7c18..c123ebc 100644 --- a/statement.c +++ b/statement.c @@ -1185,7 +1185,7 @@ SC_create_errorinfo(const StatementClass *self) } if (NULL != res->message) { - strncpy(msg, res->message, sizeof(msg)); + strncpy_null(msg, res->message, sizeof(msg)); detailmsg = resmsg = TRUE; } if (msg[0]) @@ -1216,7 +1216,7 @@ SC_create_errorinfo(const StatementClass *self) msg[pos++] = ';'; msg[pos++] = '\n'; } - strncpy(msg + pos, wmsg, sizeof(msg) - pos); + strncpy_null(msg + pos, wmsg, sizeof(msg) - pos); ermsg = msg; detailmsg = TRUE; } @@ -2529,7 +2529,8 @@ mylog("sta_pidx=%d end_pidx=%d num_p=%d\n", sta_pidx, end_pidx, num_params); qlen = (SQL_NTS == qlen) ? strlen(query) : qlen; leng = strlen(plan_name) + 1 + qlen + 1 + pileng; SOCK_put_int(sock, (Int4) (leng + 4), 4); /* length */ -inolog("parse leng=%d\n", leng); +/* inolog("parse leng=%d\n", leng); */ +inolog("parse leng=" FORMAT_SIZE_T "\n", leng); SOCK_put_string(sock, plan_name); SOCK_put_n_char(sock, query, qlen); SOCK_put_char(sock, '\0'); diff --git a/version.h b/version.h index 3b623cd..663c1d7 100644 --- a/version.h +++ b/version.h @@ -12,6 +12,6 @@ #define POSTGRESDRIVERVERSION "08.03.0401" #define POSTGRES_RESOURCE_VERSION "08.03.0401\0" #define PG_DRVFILE_VERSION 8,3,04,01 -#define PG_BUILD_VERSION "200901040002" +#define PG_BUILD_VERSION "200901180001" #endif -- 2.39.5