From 2f247b75d0e56b9ce407c91a3494228da518739e Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Sat, 3 May 2008 05:57:42 +0000 Subject: [PATCH] 1. Fix a bug in socket which uses a socket variable. 2. Support column alias without "as" so that links from the SQLServer work. 3. Take ';' into account when the driver adds "for read only" clause. 4. Use the E'.. ' notation not only in '=' expressions but also in LIKE expressions. 5. Change to return milliseconds parts for timestamp fields. 6. Change to return a specific sqlstate in case of multiple parameters. --- connection.c | 13 +- connection.h | 1 + convert.c | 60 ++++++++-- execute.c | 11 +- info.c | 174 ++++++++++++++++----------- loadlib.c | 4 +- parse.c | 333 ++++++++++++++++++++++++++++++++++++++------------- pgtypes.c | 64 ++++++---- pgtypes.h | 9 +- psqlodbc.c | 8 +- psqlodbc.h | 6 +- socket.c | 26 +++- socket.h | 2 + statement.c | 43 +++++-- statement.h | 6 +- version.h | 8 +- win64.mak | 4 +- 17 files changed, 546 insertions(+), 226 deletions(-) diff --git a/connection.c b/connection.c index bed850b..8fe67c9 100644 --- a/connection.c +++ b/connection.c @@ -224,6 +224,7 @@ PGAPI_FreeConnect( { ConnectionClass *conn = (ConnectionClass *) hdbc; CSTR func = "PGAPI_FreeConnect"; + EnvironmentClass *env; mylog("%s: entering...\n", func); mylog("**** in %s: hdbc=%p\n", func, hdbc); @@ -235,7 +236,8 @@ PGAPI_FreeConnect( } /* Remove the connection from the environment */ - if (!EN_remove_connection(conn->henv, conn)) + if (NULL != (env = CC_get_env(conn)) && + !EN_remove_connection(env, conn)) { CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func); return SQL_ERROR; @@ -317,7 +319,6 @@ reset_current_schema(ConnectionClass *self) } } -extern int exepgm; ConnectionClass * CC_Constructor() { @@ -356,7 +357,7 @@ CC_Constructor() if (VER_PLATFORM_WIN32_WINDOWS == platformId && rv->driver_version > 0x0300) rv->driver_version = 0x0300; #endif /* WIN32 */ - if (1 == exepgm) + if (isMsAccess()) rv->ms_jet = 1; rv->isolation = SQL_TXN_READ_COMMITTED; rv->mb_maxbyte_per_char = 1; @@ -3681,7 +3682,7 @@ inolog("socket=%d\n", socket); #ifdef USE_SSL sock->ssl = PQgetssl(pqconn); inolog("ssl=%p\n", sock->ssl); -#endif +#endif /* USE_SSL */ if (TRUE) { int pversion; @@ -3725,7 +3726,7 @@ if (TRUE) /* flags = fcntl(sock, F_GETFL); fcntl(sock, F_SETFL, flags & (~O_NONBLOCKING));*/ } -#endif +#endif /* USE_SSL */ mylog("Server version=%s\n", self->pg_version); ret = 1; if (ret) @@ -3777,7 +3778,7 @@ const char *CurrCat(const ConnectionClass *conn) * generates query like: "SELECT DISTINCT a FROM byronnbad3 * bad3" */ - if (2 == exepgm) /* MS Query */ + if (isMsQuery()) /* MS Query */ return NULL; else if (conn->schema_support) return conn->connInfo.database; diff --git a/connection.h b/connection.h index 44c580f..0185000 100644 --- a/connection.h +++ b/connection.h @@ -472,6 +472,7 @@ struct ConnectionClass_ /* Accessor functions */ +#define CC_get_env(x) ((x)->henv) #define CC_get_socket(x) (x->sock) #define CC_get_database(x) (x->connInfo.database) #define CC_get_server(x) (x->connInfo.server) diff --git a/convert.c b/convert.c index 6be6707..2b7001a 100644 --- a/convert.c +++ b/convert.c @@ -334,7 +334,7 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone) } static BOOL -stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) +stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, int precision) { char precstr[16], zonestr[16]; @@ -351,10 +351,12 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) strcpy(str, MINFINITY_STRING); return TRUE; } - if (precision && st->fr) + if (precision > 0 && st->fr) { sprintf(precstr, ".%09d", st->fr); - for (i = 9; i > 0; i--) + if (precision < 9) + precstr[precision + 1] = '\0'; + for (i = precision; i > 0; i--) { if (precstr[i] != '0') break; @@ -865,8 +867,12 @@ inolog("2stime fr=%d\n", std_time.fr); case PG_TYPE_TIMESTAMP: len = 19; if (cbValueMax > len) - sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", - std_time.y, std_time.m, std_time.d, std_time.hh, std_time.mm, std_time.ss); + { + /* sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", + std_time.y, std_time.m, std_time.d, std_time.hh, std_time.mm, std_time.ss); */ + stime2timestamp(&std_time, rgbValueBindRow, FALSE, PG_VERSION_GE(conn, 7.2) ? cbValueMax - len - 2 : 0); + len = strlen(rgbValueBindRow); + } break; case PG_TYPE_BOOL: @@ -2288,9 +2294,9 @@ RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb) { CSTR func = "prep_params"; RETCODE retval; - BOOL ret; + BOOL ret, once_descr; ConnectionClass *conn = SC_get_conn(stmt); - QResultClass *res; + QResultClass *res, *dest_res = NULL; char plan_name[32], multi; int func_cs_count = 0; const char *orgquery, *srvquery; @@ -2298,6 +2304,7 @@ RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb) SQLSMALLINT num_pa = 0, num_p1, num_p2; inolog("prep_params\n"); + once_descr = (ONCE_DESCRIBED == stmt->prepared); qb->flags |= FLGB_BUILDING_PREPARE_STATEMENT; for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++) { @@ -2334,7 +2341,7 @@ inolog("prep_params\n"); ret = SendParseRequest(stmt, plan_name, qb->query_statement, SQL_NTS, -1); if (!ret) goto cleanup; - if (!SendDescribeRequest(stmt, plan_name)) + if (!once_descr && (!SendDescribeRequest(stmt, plan_name))) goto cleanup; SC_set_planname(stmt, plan_name); if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe"))) @@ -2343,12 +2350,15 @@ inolog("prep_params\n"); CC_on_abort(conn, CONN_DEAD); goto cleanup; } - SC_set_Result(stmt, res); + if (once_descr) + dest_res = res; + else + SC_set_Result(stmt, res); if (!QR_command_maybe_successful(res)) { SC_set_error(stmt, STMT_EXEC_ERROR, "Error while preparing parameters", func); goto cleanup; - } + } if (stmt->multi_statement <= 0) { retval = SQL_SUCCESS; @@ -2367,7 +2377,7 @@ inolog("prep_params\n"); stmt->current_exec_param = num_pa; ret = SendParseRequest(stmt, plan_name, srvquery, endp2 < 0 ? SQL_NTS : endp2, num_p1); if (!ret) goto cleanup; - if (!SendDescribeRequest(stmt, plan_name)) + if (!once_descr && !SendDescribeRequest(stmt, plan_name)) goto cleanup; if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe"))) { @@ -2381,6 +2391,8 @@ inolog("prep_params\n"); retval = SQL_SUCCESS; cleanup: #undef return + if (dest_res) + QR_Destructor(dest_res); CLEANUP_FUNC_CONN_CS(func_cs_count, conn); stmt->current_exec_param = -1; QB_Destructor(qb); @@ -2589,8 +2601,25 @@ inolog("type=%d concur=%d\n", stmt->options.cursor_type, stmt->options.scroll_co if (0 == (qp->flags & FLGP_USING_CURSOR)) SC_no_fetchcursor(stmt); else if (0 == (qp->flags & (FLGP_SELECT_FOR_UPDATE_OR_SHARE | FLGP_SELECT_FOR_READONLY)) && + 0 == stmt->multi_statement && PG_VERSION_GE(conn, 8.3)) - CVT_APPEND_STR(qb, " for read only"); + { + BOOL semi_colon_found = FALSE; + const char *ptr = NULL, semi_colon = ';'; + int npos; + + if (npos = F_NewPos(qb) - 1, npos >= 0) + ptr = F_NewPtr(qb) - 1; + for (; npos >= 0 && isspace(*ptr); npos--, ptr--) ; + if (npos >= 0 && semi_colon == *ptr) + { + qb->npos = npos; + semi_colon_found = TRUE; + } + CVT_APPEND_STR(qb, " for read only"); + if (semi_colon_found) + CVT_APPEND_CHAR(qb, semi_colon); + } if (0 != (qp->flags & FLGP_SELECT_INTO) || 0 != (qp->flags & FLGP_MULTIPLE_STATEMENT)) { @@ -3879,7 +3908,7 @@ mylog("buf=%p flag=%d\n", buf, qb->flags); * st.m, st.d, st.hh, st.mm, st.ss); */ /* Time zone stuff is unreliable */ - stime2timestamp(&st, tmp, USE_ZONE, PG_VERSION_GE(conn, 7.2)); + stime2timestamp(&st, tmp, USE_ZONE, PG_VERSION_GE(conn, 7.2) ? 6 : 0); lastadd = "::timestamp"; CVT_APPEND_STR(qb, tmp); @@ -4285,6 +4314,11 @@ convert_escape(QueryParse *qp, QueryBuild *qb) F_OldPrior(qp); return SQL_SUCCESS; /* Continue at inner_process_tokens loop */ } + else if (stricmp(key, "escape") == 0) /* like escape support for 7.1+ servers */ + { + CVT_APPEND_STR(qb, key); + return SQL_SUCCESS; + } else if (stricmp(key, "fn") == 0) { QueryBuild nqb; diff --git a/execute.c b/execute.c index a19c48c..0d41d0f 100644 --- a/execute.c +++ b/execute.c @@ -466,7 +466,7 @@ inolog("res->next=%p\n", kres); if (res) { #if (ODBCVER >= 0x0300) - EnvironmentClass *env = (EnvironmentClass *) (conn->henv); + EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); const char *cmd = QR_get_command(res); if (retval == SQL_SUCCESS && cmd && env && EN_is_odbc3(env)) @@ -968,6 +968,10 @@ mylog("prepareParameters %d end\n", stmt->prepare); #endif /* ODBCVER */ if (recycle && !recycled) SC_recycle_statement(stmt); + if (isSqlServr() && + 0 != stmt->prepare && + STMT_TYPE_SELECT == stmt->statement_type) + parse_sqlsvr(stmt); } next_param_row: @@ -1057,7 +1061,10 @@ next_param_row: SC_set_with_hold(stmt); retval = Exec_with_parameters_resolved(stmt, &exec_end); if (!exec_end) + { + stmt->curr_param_result = 0; goto next_param_row; + } cleanup: mylog("retval=%d\n", retval); SC_setInsertedTable(stmt, retval); @@ -1101,7 +1108,7 @@ PGAPI_Transact( { conn = conns[lf]; - if (conn && conn->henv == henv) + if (conn && CC_get_env(conn) == henv) if (PGAPI_Transact(henv, (HDBC) conn, fType) != SQL_SUCCESS) return SQL_ERROR; } diff --git a/info.c b/info.c index 7003fda..9aacbf1 100644 --- a/info.c +++ b/info.c @@ -1,4 +1,4 @@ -/*-------- +/*-------- * Module: info.c * * Description: This module contains routines related to @@ -132,7 +132,7 @@ PGAPI_GetInfo( break; case SQL_COLUMN_ALIAS: /* ODBC 2.0 */ - p = "N"; + p = "Y"; break; case SQL_CONCAT_NULL_BEHAVIOR: /* ODBC 1.0 */ @@ -272,7 +272,7 @@ mylog("CONVERT_FUNCTIONS=" FORMAT_ULEN "\n", value); break; case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */ - p = "N"; + p = PG_VERSION_GE(conn, 6.5) ? "Y" : "N"; break; case SQL_FETCH_DIRECTION: /* ODBC 1.0 */ @@ -1427,14 +1427,8 @@ mylog("adjust in=%.*s(%d)\n", srclen, src, srclen); { case '%': case '_': - if (escape_ch == escape_in_literal) - dest[outlen++] = escape_in_literal; /* and insert 1 more LEXER escape */ - dest[outlen++] = escape_ch; break; default: - if (escape_ch == escape_in_literal) - dest[outlen++] = escape_in_literal; - dest[outlen++] = escape_ch; if (escape_ch == escape_in_literal) dest[outlen++] = escape_in_literal; dest[outlen++] = escape_ch; @@ -1442,14 +1436,24 @@ mylog("adjust in=%.*s(%d)\n", srclen, src, srclen); } } if (*in == escape_ch) + { escape_in = TRUE; + if (escape_ch == escape_in_literal) + dest[outlen++] = escape_in_literal; /* insert 1 more LEXER escape */ + } else { escape_in = FALSE; if (LITERAL_QUOTE == *in) dest[outlen++] = *in; - dest[outlen++] = *in; } + dest[outlen++] = *in; + } + if (escape_in) + { + if (escape_ch == escape_in_literal) + dest[outlen++] = escape_in_literal; + dest[outlen++] = escape_ch; } dest[outlen] = '\0'; if (result_len) @@ -1462,6 +1466,19 @@ mylog("adjust output=%s(%d)\n", dest, outlen); #define CSTR_TABLE "TABLE" #define CSTR_VIEW "VIEW" +CSTR like_op_sp = "like "; +CSTR like_op_ext = "like E"; +CSTR eq_op_sp = "= "; +CSTR eq_op_ext = "= E"; +static const char *gen_opestr(const char *orig_opestr, const ConnectionClass * conn) +{ + BOOL addE = (0 != CC_get_escape(conn) && PG_VERSION_GE(conn, 8.1)); + + if (0 == strcmp(orig_opestr, eqop)) + return (addE ? eq_op_ext : eq_op_sp); + return (addE ? like_op_ext : like_op_sp); +} + RETCODE SQL_API PGAPI_Tables( HSTMT hstmt, @@ -1506,7 +1523,7 @@ PGAPI_Tables( systable; int i; SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName; - const char *like_or_eq; + const char *like_or_eq, *op_string; const char *szSchemaName; BOOL search_pattern; BOOL list_cat = FALSE, list_schemas = FALSE, list_table_types = FALSE, list_some = FALSE; @@ -1607,16 +1624,17 @@ retry_public_schema: strcat(tables_query, " where relkind = 'r'"); } + op_string = gen_opestr(like_or_eq, conn); if (!list_some) { if (conn->schema_support) { - schema_strcat1(tables_query, " and nspname %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS, szTableName, cbTableName, conn); + schema_strcat1(tables_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn); /* strcat(tables_query, " and pg_catalog.pg_table_is_visible(c.oid)"); */ } else - my_strcat1(tables_query, " and usename %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS); - my_strcat1(tables_query, " and relname %s '%.*s'", like_or_eq, escTableName, SQL_NTS); + my_strcat1(tables_query, " and usename %s'%.*s'", op_string, escSchemaName, SQL_NTS); + my_strcat1(tables_query, " and relname %s'%.*s'", op_string, escTableName, SQL_NTS); } /* Parse the extra systable prefix */ @@ -1990,7 +2008,7 @@ PGAPI_Columns( ConnectionClass *conn; SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName; SQLINTEGER greloid; - const char *like_or_eq = likeop; + const char *like_or_eq = likeop, *op_string; const char *szSchemaName; mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner); @@ -2049,6 +2067,7 @@ retry_public_schema: * Create the query to find out the columns (Note: pre 6.3 did not * have the atttypmod field) */ + op_string = gen_opestr(like_or_eq, conn); if (conn->schema_support) { strncpy(columns_query, @@ -2062,8 +2081,8 @@ retry_public_schema: else { if (escTableName) - snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s '%s'", like_or_eq, escTableName); - schema_strcat1(columns_query, " and n.nspname %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS, szTableName, cbTableName, conn); + snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", op_string, escTableName); + schema_strcat1(columns_query, " and n.nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn); } strcat(columns_query, ") inner join pg_catalog.pg_attribute a" " on (not a.attisdropped)"); @@ -2075,7 +2094,7 @@ retry_public_schema: snprintf_add(columns_query, sizeof(columns_query), " and a.attnum = %d", attnum); } else if (escColumnName) - snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s '%s'", like_or_eq, escColumnName); + snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s'%s'", op_string, escColumnName); strcat(columns_query, " and a.attrelid = c.oid) inner join pg_catalog.pg_type t" " on t.oid = a.atttypid) left outer join pg_attrdef d" @@ -2093,10 +2112,10 @@ retry_public_schema: " and a.atttypid = t.oid and (a.attnum > 0)", PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod"); if (escTableName) - snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s '%s'", like_or_eq, escTableName); - my_strcat1(columns_query, " and u.usename %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS); + snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", op_string, escTableName); + my_strcat1(columns_query, " and u.usename %s'%.*s'", op_string, escSchemaName, SQL_NTS); if (escColumnName) - snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s '%s'", like_or_eq, escColumnName); + snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s'%s'", op_string, escColumnName); strcat(columns_query, " order by c.relname, attnum"); } @@ -2644,7 +2663,7 @@ PGAPI_SpecialColumns( char relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8]; BOOL relisaview; SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName; - const char *szSchemaName; + const char *szSchemaName, *eq_string; mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType); @@ -2671,7 +2690,8 @@ PGAPI_SpecialColumns( retry_public_schema: if (escSchemaName) free(escSchemaName); - escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn); + escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn); + eq_string = gen_opestr(eqop, conn); /* * Create the query to find out if this is a view or not... */ @@ -2689,12 +2709,12 @@ retry_public_schema: /* TableName cannot contain a string search pattern */ /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */ if (escTableName) - snprintf_add(columns_query, sizeof(columns_query), " and c.relname = '%s'", escTableName); + snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", eq_string, escTableName); /* SchemaName cannot contain a string search pattern */ if (conn->schema_support) - schema_strcat(columns_query, " and u.nspname = '%.*s'", escSchemaName, SQL_NTS, szTableName, cbTableName, conn); + schema_strcat1(columns_query, " and u.nspname %s'%.*s'", eq_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn); else - my_strcat(columns_query, " and u.usename = '%.*s'", escSchemaName, SQL_NTS); + my_strcat1(columns_query, " and u.usename %s'%.*s'", eq_string, escSchemaName, SQL_NTS); result = PGAPI_AllocStmt(conn, &hcol_stmt); @@ -2923,7 +2943,7 @@ PGAPI_Statistics( ConnInfo *ci; char buf[256]; SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName, field_number; - const char *szSchemaName; + const char *szSchemaName, *eq_string; OID ioid; mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner); @@ -3082,7 +3102,8 @@ PGAPI_Statistics( indx_stmt = (StatementClass *) hindx_stmt; /* TableName cannot contain a string search pattern */ - escTableName = simpleCatalogEscape(table_name, SQL_NTS, NULL, conn); + escTableName = simpleCatalogEscape(table_name, SQL_NTS, NULL, conn); + eq_string = gen_opestr(eqop, conn); if (conn->schema_support) { escSchemaName = simpleCatalogEscape(table_schemaname, SQL_NTS, NULL, conn); @@ -3092,23 +3113,23 @@ PGAPI_Statistics( " from pg_catalog.pg_index i, pg_catalog.pg_class c," " pg_catalog.pg_class d, pg_catalog.pg_am a," " pg_catalog.pg_namespace n" - " where d.relname = '%s'" - " and n.nspname = '%s'" + " where d.relname %s'%s'" + " and n.nspname %s'%s'" " and n.oid = d.relnamespace" " and d.oid = i.indrelid" " and i.indexrelid = c.oid" " and c.relam = a.oid order by" - ,escTableName, escSchemaName); + , eq_string, escTableName, eq_string, escSchemaName); } else snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique" ", i.indisclustered, a.amname, c.relhasrules, c.oid" " from pg_index i, pg_class c, pg_class d, pg_am a" - " where d.relname = '%s'" + " where d.relname %s'%s'" " and d.oid = i.indrelid" " and i.indexrelid = c.oid" " and c.relam = a.oid order by" - ,escTableName); + , eq_string, escTableName); if (PG_VERSION_GT(SC_get_conn(stmt), 6.4)) strcat(index_query, " i.indisprimary desc,"); if (conn->schema_support) @@ -3389,7 +3410,7 @@ PGAPI_ColumnPrivileges( ConnectionClass *conn = SC_get_conn(stmt); RETCODE result = SQL_ERROR; char *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL; - const char *like_or_eq; + const char *like_or_eq, *op_string, *eq_string; char column_query[INFO_INQUIRY_LEN]; size_t cq_len,cq_size; char *col_query; @@ -3424,12 +3445,14 @@ PGAPI_ColumnPrivileges( cq_len = strlen(column_query); cq_size = sizeof(column_query); col_query = column_query; + op_string = gen_opestr(like_or_eq, conn); + eq_string = gen_opestr(eqop, conn); if (escSchemaName) { col_query += cq_len; cq_size -= cq_len; cq_len = snprintf_len(col_query, cq_size, - " and table_schem = '%s'", escSchemaName); + " and table_schem %s'%s'", eq_string, escSchemaName); } if (escTableName) @@ -3437,14 +3460,14 @@ PGAPI_ColumnPrivileges( col_query += cq_len; cq_size -= cq_len; cq_len += snprintf_len(col_query, cq_size, - " and table_name = '%s'", escTableName); + " and table_name %s'%s'", eq_string, escTableName); } if (escColumnName) { col_query += cq_len; cq_size -= cq_len; cq_len += snprintf_len(col_query, cq_size, - " and column_name %s '%s'", like_or_eq, escColumnName); + " and column_name %s'%s'", op_string, escColumnName); } if (res = CC_send_query(conn, column_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res)) { @@ -3515,7 +3538,7 @@ PGAPI_PrimaryKeys( qstart, qend; SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName; - const char *szSchemaName; + const char *szSchemaName, *eq_string; char *escSchemaName = NULL, *escTableName = NULL; mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner); @@ -3582,6 +3605,7 @@ PGAPI_PrimaryKeys( cbSchemaName = cbTableOwner; escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn); } + eq_string = gen_opestr(eqop, conn); retry_public_schema: pkscm[0] = '\0'; @@ -3663,9 +3687,9 @@ retry_public_schema: tbqry = tables_query + qsize; if (0 == reloid) snprintf(tbqry, tsize, - " where tc.relname = '%s'" - " AND n.nspname = '%s'" - , escTableName, pkscm); + " where tc.relname %s'%s'" + " AND n.nspname %s'%s'" + , eq_string, escTableName, eq_string, pkscm); else snprintf(tbqry, tsize, " where tc.oid = " FORMAT_UINTEGER @@ -3695,8 +3719,8 @@ retry_public_schema: tbqry = tables_query + qsize; if (0 == reloid) snprintf(tbqry, tsize, - " where tc.relname = '%s'" - , escTableName); + " where tc.relname %s'%s'" + , eq_string, escTableName); else snprintf(tbqry, tsize, " where tc.oid = " FORMAT_UINTEGER, reloid); @@ -3722,8 +3746,8 @@ retry_public_schema: " from pg_catalog.pg_attribute ta," " pg_catalog.pg_attribute ia, pg_catalog.pg_class ic," " pg_catalog.pg_index i, pg_catalog.pg_namespace n" - " where ic.relname = '%s_pkey'" - " AND n.nspname = '%s'" + " where ic.relname %s'%s_pkey'" + " AND n.nspname %s'%s'" " AND ic.oid = i.indexrelid" " AND n.oid = ic.relnamespace" " AND ia.attrelid = i.indexrelid" @@ -3731,16 +3755,16 @@ retry_public_schema: " AND ta.attnum = i.indkey[ia.attnum-1]" " AND (NOT ta.attisdropped)" " AND (NOT ia.attisdropped)" - " order by ia.attnum", escTableName, pkscm); + " order by ia.attnum", eq_string, escTableName, eq_string, pkscm); else snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum, ic.relname, NULL, NULL" " from pg_attribute ta, pg_attribute ia, pg_class ic, pg_index i" - " where ic.relname = '%s_pkey'" + " where ic.relname %s'%s_pkey'" " AND ic.oid = i.indexrelid" " AND ia.attrelid = i.indexrelid" " AND ta.attrelid = i.indrelid" " AND ta.attnum = i.indkey[ia.attnum-1]" - " order by ia.attnum", escTableName); + " order by ia.attnum", eq_string, escTableName); break; } mylog("%s: tables_query='%s'\n", func, tables_query); @@ -3866,6 +3890,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, { char query[1024], saveattnum[16], *ret = serverColumnName; + const char *eq_string; BOOL continueExec = TRUE, bError = FALSE; QResultClass *res = NULL; @@ -3889,11 +3914,12 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding); bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL)))); QR_Destructor(res); + eq_string = gen_opestr(eqop, conn); if (!bError && continueExec) { snprintf(query, sizeof(query), "select attnum from pg_attribute " - "where attrelid = %u and attname = '%s'", - relid, serverColumnName); + "where attrelid = %u and attname %s'%s'", + relid, eq_string, serverColumnName); if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res)) { if (QR_get_num_cached_tuples(res) > 0) @@ -3986,6 +4012,7 @@ PGAPI_ForeignKeys( char pkey[MAX_INFO_STRING]; Int2 result_cols; UInt4 relid1, relid2; + const char *eq_string; mylog("%s: entering...stmt=%p\n", func, stmt); @@ -4063,6 +4090,7 @@ PGAPI_ForeignKeys( #endif /* UNICODE_SUPPORT */ pkey_alloced = fkey_alloced = FALSE; + eq_string = gen_opestr(eqop, conn); /* * Case #2 -- Get the foreign keys in the specified table (fktab) that * refer to the primary keys of other table(s). @@ -4103,9 +4131,9 @@ PGAPI_ForeignKeys( "AND pp1.oid = pt1.tgfoid " "AND pt2.tgfoid = pp2.oid " "AND pt2.tgconstrrelid = pc.oid " - "AND ((pc.relname='%s') " + "AND ((pc.relname %s'%s') " "AND (pn1.oid = pc.relnamespace) " - "AND (pn1.nspname = '%s') " + "AND (pn1.nspname %s'%s') " "AND (pp.proname LIKE '%%ins') " "AND (pp1.proname LIKE '%%upd') " "AND (pp1.proname not LIKE '%%check%%') " @@ -4117,7 +4145,7 @@ PGAPI_ForeignKeys( "AND (pt.tgconstrrelid=pc1.oid) " "AND (pc1.relnamespace=pn.oid))" " order by pt.tgconstrname", - escFkTableName, escSchemaName); + eq_string, escFkTableName, eq_string, escSchemaName); free(escSchemaName); } else @@ -4144,7 +4172,7 @@ PGAPI_ForeignKeys( "AND pp1.oid = pt1.tgfoid " "AND pt2.tgfoid = pp2.oid " "AND pt2.tgconstrrelid = pc.oid " - "AND ((pc.relname='%s') " + "AND ((pc.relname %s'%s') " "AND (pp.proname LIKE '%%ins') " "AND (pp1.proname LIKE '%%upd') " "AND (pp1.proname not LIKE '%%check%%') " @@ -4155,7 +4183,7 @@ PGAPI_ForeignKeys( "AND (pt2.tgconstrname=pt.tgconstrname) " "AND (pt.tgconstrrelid=pc1.oid)) " "order by pt.tgconstrname", - escFkTableName); + eq_string, escFkTableName); result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0); @@ -4467,8 +4495,8 @@ PGAPI_ForeignKeys( " pg_catalog.pg_trigger pt2, " " pg_catalog.pg_namespace pn, " " pg_catalog.pg_namespace pn1 " - "WHERE pc.relname='%s' " - " AND pn.nspname = '%s' " + "WHERE pc.relname %s'%s' " + " AND pn.nspname %s'%s' " " AND pc.relnamespace = pn.oid " " AND pt.tgconstrrelid = pc.oid " " AND pp.oid = pt.tgfoid " @@ -4487,7 +4515,7 @@ PGAPI_ForeignKeys( " AND pp2.proname Like '%%del' " " AND pn1.oid = pc1.relnamespace " " order by pt.tgconstrname", - escPkTableName, escSchemaName); + eq_string, escPkTableName, eq_string, escSchemaName); free(escSchemaName); } else @@ -4508,7 +4536,7 @@ PGAPI_ForeignKeys( " pg_trigger pt, " " pg_trigger pt1, " " pg_trigger pt2 " - "WHERE pc.relname ='%s' " + "WHERE pc.relname %s'%s' " " AND pt.tgconstrrelid = pc.oid " " AND pp.oid = pt.tgfoid " " AND pp.proname Like '%%ins' " @@ -4525,7 +4553,7 @@ PGAPI_ForeignKeys( " AND pp2.oid = pt2.tgfoid " " AND pp2.proname Like '%%del'" " order by pt.tgconstrname", - escPkTableName); + eq_string, escPkTableName); result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0); if (!SQL_SUCCEEDED(result)) @@ -4840,7 +4868,7 @@ PGAPI_ProcedureColumns( Int4 paramcount, i, j; RETCODE result; BOOL search_pattern, bRetset; - const char *like_or_eq, *retset; + const char *like_or_eq, *op_string, *retset; int ret_col = -1, ext_pos = -1, poid_pos = -1, attid_pos = -1, attname_pos = -1; UInt4 poid = 0, newpoid; @@ -4866,6 +4894,7 @@ PGAPI_ProcedureColumns( escSchemaName = simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn); escProcName = simpleCatalogEscape(szProcName, cbProcName, NULL, conn); } + op_string = gen_opestr(like_or_eq, conn); if (conn->schema_support) { strcpy(proc_query, "select proname, proretset, prorettype, " @@ -4902,9 +4931,9 @@ PGAPI_ProcedureColumns( " (not proretset) and"); #endif /* PRORET_COUNT */ strcat(proc_query, " has_function_privilege(p.oid, 'EXECUTE')"); - my_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS); + my_strcat1(proc_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS); if (escProcName) - snprintf_add(proc_query, sizeof(proc_query), " and proname %s '%s'", like_or_eq, escProcName); + snprintf_add(proc_query, sizeof(proc_query), " and proname %s'%s'", op_string, escProcName); strcat(proc_query, " order by nspname, proname, p.oid, attnum"); } else @@ -4914,7 +4943,7 @@ PGAPI_ProcedureColumns( "(not proretset)"); ret_col = 5; if (escProcName) - snprintf_add(proc_query, sizeof(proc_query), " and proname %s '%s'", like_or_eq, escProcName); + snprintf_add(proc_query, sizeof(proc_query), " and proname %s'%s'", op_string, escProcName); strcat(proc_query, " order by proname, proretset"); } if (tres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(tres)) @@ -5234,7 +5263,7 @@ PGAPI_Procedures( char *escSchemaName = NULL, *escProcName = NULL; QResultClass *res; RETCODE result; - const char *like_or_eq; + const char *like_or_eq, *op_string; BOOL search_pattern; mylog("%s: entering... scnm=%p len=%d\n", func, szProcOwner, cbProcOwner); @@ -5263,6 +5292,7 @@ PGAPI_Procedures( /* * The following seems the simplest implementation */ + op_string = gen_opestr(like_or_eq, conn); if (conn->schema_support) { strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", nspname as " "PROCEDURE_SCHEM" "," @@ -5273,8 +5303,8 @@ PGAPI_Procedures( " as " "PROCEDURE_TYPE" " from pg_catalog.pg_namespace," " pg_catalog.pg_proc" " where pg_proc.pronamespace = pg_namespace.oid"); - schema_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS, szProcName, cbProcName, conn); - my_strcat1(proc_query, " and proname %s '%.*s'", like_or_eq, escProcName, SQL_NTS); + schema_strcat1(proc_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szProcName, cbProcName, conn); + my_strcat1(proc_query, " and proname %s'%.*s'", op_string, escProcName, SQL_NTS); } else { @@ -5283,7 +5313,7 @@ PGAPI_Procedures( " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" "," " '' as " "REMARKS" "," " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc"); - my_strcat1(proc_query, " where proname %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS); + my_strcat1(proc_query, " where proname %s'%.*s'", op_string, escSchemaName, SQL_NTS); } if (res = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res)) @@ -5382,7 +5412,7 @@ PGAPI_TablePrivileges( char (*useracl)[ACLMAX] = NULL, *acl, *user, *delim, *auth; const char *reln, *owner, *priv, *schnm = NULL; RETCODE result, ret = SQL_SUCCESS; - const char *like_or_eq; + const char *like_or_eq, *op_string; const char *szSchemaName; SQLSMALLINT cbSchemaName; char *escSchemaName = NULL, *escTableName = NULL; @@ -5444,6 +5474,8 @@ retry_public_schema: escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn); else escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn); + + op_string = gen_opestr(like_or_eq, conn); if (conn->schema_support) strncpy_null(proc_query, "select relname, usename, relacl, nspname" " from pg_catalog.pg_namespace, pg_catalog.pg_class ," @@ -5454,10 +5486,10 @@ retry_public_schema: if (conn->schema_support) { if (escSchemaName) - schema_strcat1(proc_query, " nspname %s '%.*s' and", like_or_eq, escSchemaName, SQL_NTS, szTableName, cbTableName, conn); + schema_strcat1(proc_query, " nspname %s'%.*s' and", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn); } if (escTableName) - snprintf_add(proc_query, sizeof(proc_query), " relname %s '%s' and", like_or_eq, escTableName); + snprintf_add(proc_query, sizeof(proc_query), " relname %s'%s' and", op_string, escTableName); if (conn->schema_support) { strcat(proc_query, " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and"); diff --git a/loadlib.c b/loadlib.c index 88c0b84..1ad6348 100644 --- a/loadlib.c +++ b/loadlib.c @@ -222,9 +222,9 @@ void *CALL_PQconnectdb(const char *conninfo, BOOL *libpqLoaded) { loaded_libpq = TRUE; /* ssllibs are already loaded by libpq - if (PQgetssl(pqconn)) */ + if (PQgetssl(pqconn)) loaded_ssllib = TRUE; - + */ } #else pqconn = PQconnectdb(conninfo); diff --git a/parse.c b/parse.c index 29ec2c8..a9cb9dc 100644 --- a/parse.c +++ b/parse.c @@ -1051,11 +1051,63 @@ cleanup: return ret; } -char -parse_statement(StatementClass *stmt, BOOL check_hasoids) +static BOOL include_alias_wo_as(const char *token, const char *btoken) +{ +mylog("alias ? token=%s btoken=%s\n", token, btoken); + if ('\0' == btoken[0]) + return FALSE; + else if (0 == stricmp(")", token)) + return FALSE; + else if (0 == stricmp("as", btoken) || + 0 == stricmp("and", btoken) || + 0 == stricmp("or", btoken) || + 0 == stricmp("not", btoken) || + 0 == stricmp(",", btoken)) + return FALSE; + else + { + CSTR ops = "+-*/%^|!@&#~<>=."; + const char *cptr, *optr; + + for (cptr = btoken; *cptr; cptr++) + { + for (optr = ops; *optr; optr++) + { + if (*optr != *cptr) + return TRUE; + } + } + } + + return FALSE; +} + +static char *insert_as_to_the_statement(char *stmt, char **pptr, char **ptr) +{ + size_t stsize = strlen(stmt), ppos = *pptr - stmt, remsize = stsize - ppos; + const int ins_size = 3; + char *newstmt = realloc(stmt, stsize + ins_size + 1); + + if (newstmt) + { + char *sptr = newstmt + ppos; + memmove(sptr + ins_size, sptr, remsize + 1); + sptr[0] = 'a'; + sptr[1] = 's'; + sptr[2] = ' '; + *ptr = sptr + (*ptr - *pptr) + ins_size; + *pptr = sptr + ins_size; + } + + return newstmt; +} + +#define TOKEN_SIZE 256 +static char +parse_the_statement(StatementClass *stmt, BOOL check_hasoids, BOOL sqlsvr_check) { CSTR func = "parse_statement"; - char token[256], stoken[256]; + char token[TOKEN_SIZE], stoken[TOKEN_SIZE], btoken[TOKEN_SIZE]; char delim, quote, dquote, @@ -1080,13 +1132,14 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) k = 0, n, blevel = 0, old_blevel, subqlevel = 0, - allocated_size, new_size; + tbl_blevel = 0, allocated_size, new_size, + nfields; FIELD_INFO **fi, *wfi; TABLE_INFO **ti, *wti; char parse, maybe_join = 0; ConnectionClass *conn = SC_get_conn(stmt); - IRDFields *irdflds = SC_get_IRDF(stmt); - BOOL updatable = TRUE; + IRDFields *irdflds; + BOOL updatable = TRUE, column_has_alias; mylog("%s: entering...\n", func); @@ -1096,18 +1149,33 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) CheckHasOids(stmt); return TRUE; } - stmt->updatable = FALSE; + nfields = 0; + wfi = NULL; + wti = NULL; ptr = stmt->statement; - fi = irdflds->fi; - ti = stmt->ti; + if (sqlsvr_check) + { + irdflds = NULL; + fi = NULL; + ti = NULL; + } + else + { + stmt->updatable = FALSE; + irdflds = SC_get_IRDF(stmt); + fi = irdflds->fi; + ti = stmt->ti; - allocated_size = irdflds->allocated; - SC_initialize_cols_info(stmt, FALSE, TRUE); - stmt->from_pos = -1; - stmt->where_pos = -1; + allocated_size = irdflds->allocated; + SC_initialize_cols_info(stmt, FALSE, TRUE); + stmt->from_pos = -1; + stmt->where_pos = -1; + } #define return DONT_CALL_RETURN_FROM_HERE??? - while (pptr = ptr, (ptr = getNextToken(conn->ccsc, CC_get_escape(conn), pptr, token, sizeof(token), &delim, "e, &dquote, &numeric)) != NULL) + delim = '\0'; + token[0] = '\0'; + while (pptr = ptr, (delim != ',') ? strcpy(btoken, token) : (char *) (btoken[0] = '\0'), (ptr = getNextToken(conn->ccsc, CC_get_escape(conn), pptr, token, sizeof(token), &delim, "e, &dquote, &numeric)) != NULL) { unquoted = !(quote || dquote); @@ -1136,6 +1204,11 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) } else if (!stricmp(token, "from")) { + if (sqlsvr_check) + { + parse = TRUE; + goto cleanup; + } in_select = FALSE; in_from = TRUE; if (stmt->from_pos < 0 && @@ -1222,6 +1295,30 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) } if (in_select) { +mylog("blevel=%d btoken=%s in_dot=%d in_field=%d tbname=%s\n", blevel, btoken, in_dot, in_field, wfi ? SAFE_NAME(wfi->column_alias) : ""); + if (0 == blevel && + sqlsvr_check && + dquote && + '\0' != btoken[0] && + !in_dot && + in_field && + (!column_has_alias)) + { + if (include_alias_wo_as(token, btoken)) + { + char *news; + + column_has_alias = TRUE; + if (NULL != wfi) + STR_TO_NAME(wfi->column_alias, token); + news = insert_as_to_the_statement(stmt->statement, &pptr, &ptr); + if (news != stmt->statement) + { + free(stmt->statement); + stmt->statement = news; + } + } + } if (in_expr || in_func) { /* just eat the expression */ @@ -1275,85 +1372,101 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) if (!token[0]) continue; - /* if (!(irdflds->nfields % FLD_INCR)) */ - if (irdflds->nfields >= allocated_size) + column_has_alias = FALSE; + if (!sqlsvr_check) { - mylog("reallocing at nfld=%d\n", irdflds->nfields); - new_size = irdflds->nfields + 1; - if (!allocateFields(irdflds, new_size)) + /* if (!(irdflds->nfields % FLD_INCR)) */ + if (irdflds->nfields >= allocated_size) + { + mylog("reallocing at nfld=%d\n", irdflds->nfields); + new_size = irdflds->nfields + 1; + if (!allocateFields(irdflds, new_size)) + { + SC_set_parse_status(stmt, STMT_PARSE_FATAL); + SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO.", func); + goto cleanup; + } + fi = irdflds->fi; + allocated_size = irdflds->allocated; + } + + wfi = fi[irdflds->nfields]; + if (NULL != wfi) + fi_reuse = TRUE; + else + wfi = fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO)); + if (NULL == wfi) { SC_set_parse_status(stmt, STMT_PARSE_FATAL); - SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO.", func); + SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO(2).", func); goto cleanup; } - fi = irdflds->fi; - allocated_size = irdflds->allocated; - } - wfi = fi[irdflds->nfields]; - if (wfi) - fi_reuse = TRUE; - else - wfi = fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO)); - if (wfi == NULL) - { - SC_set_parse_status(stmt, STMT_PARSE_FATAL); - SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO(2).", func); - goto cleanup; + /* Initialize the field info */ + FI_Constructor(wfi, fi_reuse); + wfi->flag = FIELD_PARSING; } - /* Initialize the field info */ - FI_Constructor(wfi, fi_reuse); - wfi->flag = FIELD_PARSING; - /* double quotes are for qualifiers */ - if (dquote) + if (dquote && NULL != wfi) wfi->dquote = TRUE; if (quote) { - wfi->quote = TRUE; - wfi->column_size = (int) strlen(token); + if (NULL != wfi) + { + wfi->quote = TRUE; + wfi->column_size = (int) strlen(token); + } } else if (numeric) { - mylog("**** got numeric: nfld = %d\n", irdflds->nfields); - wfi->numeric = TRUE; + mylog("**** got numeric: nfld = %d\n", nfields); + if (NULL != wfi) + wfi->numeric = TRUE; } else if (0 == old_blevel && blevel > 0) { /* expression */ mylog("got EXPRESSION\n"); - wfi->expr = TRUE; + if (NULL != wfi) + wfi->expr = TRUE; in_expr = TRUE; /* continue; */ } - else + else if (NULL != wfi) { STR_TO_NAME(wfi->column_name, token); NULL_THE_NAME(wfi->before_dot); } - mylog("got field='%s', dot='%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->before_dot)); + if (NULL != wfi) + mylog("got field='%s', dot='%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->before_dot)); if (delim == ',') mylog("comma (1)\n"); else in_field = TRUE; - irdflds->nfields++; + nfields++; + if (NULL != irdflds) + irdflds->nfields++; continue; } /* !in_field */ /* * We are in a field now */ - wfi = fi[irdflds->nfields - 1]; + if (!sqlsvr_check) + wfi = fi[irdflds->nfields - 1]; if (in_dot) { - if (NAME_IS_VALID(wfi->before_dot)) + if (NULL != wfi) { - MOVE_NAME(wfi->schema_name, wfi->before_dot); + if (NAME_IS_VALID(wfi->before_dot)) + { + MOVE_NAME(wfi->schema_name, wfi->before_dot); + } + MOVE_NAME(wfi->before_dot, wfi->column_name); + STR_TO_NAME(wfi->column_name, token); } - MOVE_NAME(wfi->before_dot, wfi->column_name); - STR_TO_NAME(wfi->column_name, token); if (delim == ',') { @@ -1366,8 +1479,12 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) if (in_as) { - STR_TO_NAME(wfi->column_alias, token); - mylog("alias for field '%s' is '%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias)); + column_has_alias = TRUE; + if (NULL != wfi) + { + STR_TO_NAME(wfi->column_alias, token); + mylog("alias for field '%s' is '%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias)); + } in_as = FALSE; in_field = FALSE; @@ -1381,7 +1498,8 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) { in_dot = FALSE; in_func = TRUE; - wfi->func = TRUE; + if (NULL != wfi) + wfi->func = TRUE; /* * name will have the function name -- maybe useful some @@ -1407,11 +1525,23 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) } /* otherwise, it's probably an expression */ - in_expr = TRUE; - wfi->expr = TRUE; - NULL_THE_NAME(wfi->column_name); - wfi->column_size = 0; - mylog("*** setting expression\n"); + if (!column_has_alias) + { + in_expr = TRUE; + if (NULL != wfi) + { + wfi->expr = TRUE; + NULL_THE_NAME(wfi->column_name); + wfi->column_size = 0; + } + mylog("*** setting expression\n"); + } + else + mylog("*** may be an alias for a field\n"); + if (0 == blevel && ',' == delim) + { + in_expr = in_func = in_field = FALSE; + } } /* in_select end */ if (in_from || in_where) @@ -1434,7 +1564,7 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) } if (out_table && !in_table) /* new table */ { - BOOL is_table_name; + BOOL is_table_name, is_subquery; in_dot = FALSE; maybe_join = 0; @@ -1445,37 +1575,47 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) continue; } - if (!increaseNtab(stmt, func)) + if (sqlsvr_check) + wti = NULL; + else { - SC_set_parse_status(stmt, STMT_PARSE_FATAL); - goto cleanup; - } + if (!increaseNtab(stmt, func)) + { + SC_set_parse_status(stmt, STMT_PARSE_FATAL); + goto cleanup; + } - ti = stmt->ti; - wti = ti[stmt->ntab - 1]; + ti = stmt->ti; + wti = ti[stmt->ntab - 1]; + } is_table_name = TRUE; + is_subquery = FALSE; if (dquote) ; else if (0 == stricmp(token, "select")) { mylog("got subquery lvl=%d\n", blevel); is_table_name = FALSE; + is_subquery = TRUE; } else if ('(' == ptr[0]) { mylog("got srf? = '%s'\n", token); is_table_name = FALSE; } - if (is_table_name) - { - STR_TO_NAME(wti->table_name, token); - lower_the_name(GET_NAME(wti->table_name), conn, dquote); - mylog("got table = '%s'\n", PRINT_NAME(wti->table_name)); - } - else + if (NULL != wti) { - NULL_THE_NAME(wti->table_name); - TI_no_updatable(wti); + if (is_table_name) + { + STR_TO_NAME(wti->table_name, token); + lower_the_name(GET_NAME(wti->table_name), conn, dquote); + mylog("got table = '%s'\n", PRINT_NAME(wti->table_name)); + } + else + { + NULL_THE_NAME(wti->table_name); + TI_no_updatable(wti); + } } if (0 == blevel && delim == ',') @@ -1487,10 +1627,14 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) { out_table = FALSE; in_table = TRUE; + if (is_subquery) + tbl_blevel = blevel - 1; + else + tbl_blevel = blevel; } continue; } - if (0 != blevel) + if (blevel > tbl_blevel) continue; /* out_table is FALSE here */ if (!dquote && !in_dot) @@ -1533,12 +1677,16 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) maybe_join = 0; if (in_table) { - wti = ti[stmt->ntab - 1]; + if (!sqlsvr_check) + wti = ti[stmt->ntab - 1]; if (in_dot) { - MOVE_NAME(wti->schema_name, wti->table_name); - STR_TO_NAME(wti->table_name, token); - lower_the_name(GET_NAME(wti->table_name), conn, dquote); + if (NULL != wfi) + { + MOVE_NAME(wti->schema_name, wti->table_name); + STR_TO_NAME(wti->table_name, token); + lower_the_name(GET_NAME(wti->table_name), conn, dquote); + } in_dot = FALSE; continue; } @@ -1557,8 +1705,11 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) continue; } } - STR_TO_NAME(wti->table_alias, token); - mylog("alias for table '%s' is '%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias)); + if (NULL != wti) + { + STR_TO_NAME(wti->table_alias, token); + mylog("alias for table '%s' is '%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias)); + } in_table = FALSE; if (delim == ',') { @@ -1575,6 +1726,8 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) */ parse = TRUE; + if (sqlsvr_check) + goto cleanup; /* Resolve field names with tables */ for (i = 0; i < (int) irdflds->nfields; i++) @@ -1875,12 +2028,24 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids) stmt->updatable = updatable; cleanup: #undef return - if (STMT_PARSE_FATAL == SC_parsed_status(stmt)) + if (!sqlsvr_check && STMT_PARSE_FATAL == SC_parsed_status(stmt)) { SC_initialize_cols_info(stmt, FALSE, FALSE); parse = FALSE; } - mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, SC_parsed_status(stmt)); + mylog("done %s: parse=%d, parse_status=%d\n", func, parse, SC_parsed_status(stmt)); return parse; } + +char +parse_statement(StatementClass *stmt, BOOL check_hasoids) +{ + return parse_the_statement(stmt, check_hasoids, FALSE); +} + +char +parse_sqlsvr(StatementClass *stmt) +{ + return parse_the_statement(stmt, FALSE, TRUE); +} diff --git a/pgtypes.c b/pgtypes.c index 418ed16..2923a9a 100644 --- a/pgtypes.c +++ b/pgtypes.c @@ -360,6 +360,10 @@ pgtype_to_concise_type(StatementClass *stmt, OID type, int col) return ci->drivers.bools_as_char ? SQL_CHAR : SQL_BIT; case PG_TYPE_XML: return CC_is_in_unicode_driver(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR; + case PG_TYPE_INET: + case PG_TYPE_CIDR: + case PG_TYPE_MACADDR: + return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR; default: /* @@ -480,7 +484,7 @@ pgtype_to_ctype(StatementClass *stmt, OID type) case PG_TYPE_TEXT: if (CC_is_in_unicode_driver(conn) #ifdef NOT_USED - && ! stmt->catalog_result) + && ! stmt->catalog_result #endif /* NOT USED */ ) return SQL_C_WCHAR; @@ -564,6 +568,14 @@ inolog("pgtype_to_name int4\n"); return "bool"; case PG_TYPE_BYTEA: return "bytea"; + case PG_TYPE_XML: + return "xml"; + case PG_TYPE_MACADDR: + return "macaddr"; + case PG_TYPE_INET: + return "inet"; + case PG_TYPE_CIDR: + return "cidr"; case PG_TYPE_LO_UNDEFINED: return PG_TYPE_LO_NAME; @@ -704,6 +716,12 @@ getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_si maxsize = ci->drivers.max_varchar_size; break; } +#ifdef UNICODE_SUPPORT + if (CC_is_in_unicode_driver(conn) && + isSqlServr() && + maxsize > 4000) + maxsize = 4000; +#endif /* UNICODE_SUPPORT */ if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */ { @@ -755,15 +773,23 @@ getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_si } } - if (maxsize <= 0) - return maxsize; /* The type is really unknown */ - if (type == PG_TYPE_BPCHAR) + switch (handle_unknown_size_as) { - mylog("%s: BP_CHAR LONGEST: p = %d\n", func, p); - if (p > 0) - return p; + case UNKNOWNS_AS_DONTKNOW: + return -1; + case UNKNOWNS_AS_LONGEST: + mylog("%s: LONGEST: p = %d\n", func, p); + if (p > 0) + return p; + break; + case UNKNOWNS_AS_MAX: + break; + default: + return -1; } + if (maxsize <= 0) + return maxsize; switch (type) { case PG_TYPE_BPCHAR: @@ -771,19 +797,10 @@ getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_si case PG_TYPE_TEXT: return maxsize; } - if (handle_unknown_size_as == UNKNOWNS_AS_LONGEST) - { - mylog("%s: LONGEST: p = %d\n", func, p); - if (p > 0) - return p; - } if (p > maxsize) maxsize = p; - if (handle_unknown_size_as == UNKNOWNS_AS_MAX) - return maxsize; - else /* handle_unknown_size_as == DONT_KNOW */ - return -1; + return maxsize; } static SQLSMALLINT @@ -930,6 +947,13 @@ pgtype_column_size(StatementClass *stmt, OID type, int col, int handle_unknown_s case PG_TYPE_BOOL: return ci->true_is_minus1 ? 2 : 1; + case PG_TYPE_MACADDR: + return 17; + + case PG_TYPE_INET: + case PG_TYPE_CIDR: + return sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128"); + case PG_TYPE_LO_UNDEFINED: return SQL_NO_TOTAL; @@ -1416,7 +1440,7 @@ pgtype_unsigned(StatementClass *stmt, OID type) } -char * +const char * pgtype_literal_prefix(StatementClass *stmt, OID type) { switch (type) @@ -1438,7 +1462,7 @@ pgtype_literal_prefix(StatementClass *stmt, OID type) } -char * +const char * pgtype_literal_suffix(StatementClass *stmt, OID type) { switch (type) @@ -1460,7 +1484,7 @@ pgtype_literal_suffix(StatementClass *stmt, OID type) } -char * +const char * pgtype_create_params(StatementClass *stmt, OID type) { switch (type) diff --git a/pgtypes.h b/pgtypes.h index a013026..2242e3e 100644 --- a/pgtypes.h +++ b/pgtypes.h @@ -47,6 +47,7 @@ #define PG_TYPE_BOX 603 #define PG_TYPE_POLYGON 604 #define PG_TYPE_FILENAME 605 +#define PG_TYPE_CIDR 650 #define PG_TYPE_FLOAT4 700 #define PG_TYPE_FLOAT8 701 #define PG_TYPE_ABSTIME 702 @@ -55,6 +56,8 @@ #define PG_TYPE_UNKNOWN 705 #define PG_TYPE_MONEY 790 #define PG_TYPE_OIDINT2 810 +#define PG_TYPE_MACADDR 829 +#define PG_TYPE_INET 869 #define PG_TYPE_OIDINT4 910 #define PG_TYPE_OIDNAME 911 #define PG_TYPE_TEXTARRAY 1009 @@ -107,9 +110,9 @@ Int2 pgtype_case_sensitive(StatementClass *stmt, OID type); Int2 pgtype_money(StatementClass *stmt, OID type); Int2 pgtype_searchable(StatementClass *stmt, OID type); Int2 pgtype_unsigned(StatementClass *stmt, OID type); -char *pgtype_literal_prefix(StatementClass *stmt, OID type); -char *pgtype_literal_suffix(StatementClass *stmt, OID type); -char *pgtype_create_params(StatementClass *stmt, OID type); +const char *pgtype_literal_prefix(StatementClass *stmt, OID type); +const char *pgtype_literal_suffix(StatementClass *stmt, OID type); +const char *pgtype_create_params(StatementClass *stmt, OID type); SQLSMALLINT sqltype_to_default_ctype(const ConnectionClass *stmt, SQLSMALLINT sqltype); Int4 ctype_length(SQLSMALLINT ctype); diff --git a/psqlodbc.c b/psqlodbc.c index d7c3999..a748bf0 100644 --- a/psqlodbc.c +++ b/psqlodbc.c @@ -27,7 +27,11 @@ int platformId = 0; #endif -int exepgm = 0; +static int exepgm = 0; +BOOL isMsAccess() {return 1 == exepgm;} +BOOL isMsQuery() {return 2 == exepgm;} +BOOL isSqlServr() {return 3 == exepgm;} + GLOBAL_VALUES globals; RETCODE SQL_API SQLDummyOrdinal(void); @@ -124,6 +128,8 @@ DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) exepgm = 1; else if (strnicmp(fname, "msqry", 5) == 0) exepgm = 2; + else if (strnicmp(fname, "sqlservr", 8) == 0) + exepgm = 3; } osversion.dwOSVersionInfoSize = sizeof(osversion); if (GetVersionEx(&osversion)) diff --git a/psqlodbc.h b/psqlodbc.h index 8719b5c..4d189c3 100644 --- a/psqlodbc.h +++ b/psqlodbc.h @@ -5,7 +5,7 @@ * * Comments: See "notice.txt" for copyright and license information. * - * $Id: psqlodbc.h,v 1.121 2007/12/26 13:28:36 hinoue Exp $ + * $Id: psqlodbc.h,v 1.122 2008/05/03 05:57:42 hinoue Exp $ * */ @@ -235,6 +235,9 @@ typedef double SDOUBLE; #else #define DRIVER_FILE_NAME "PSQLODBC25.DLL" #endif /* ODBCVER 0x0300 */ +BOOL isMsAccess(); +BOOL isMsQuery(); +BOOL isSqlServr(); #else #ifdef UNICODE_SUPPORT #define DRIVER_FILE_NAME "psqlodbcw.so" @@ -468,6 +471,7 @@ SQLULEN utf8_to_ucs2_lf(const char * utf8str, SQLLEN ilen, BOOL lfconv, SQLWCHAR #define utf8_to_ucs2(utf8str, ilen, ucs2str, buflen) utf8_to_ucs2_lf(utf8str, ilen, FALSE, ucs2str, buflen) #endif /* UNICODE_SUPPORT */ + #ifdef _MEMORY_DEBUG_ void *debug_alloc(size_t); void *debug_calloc(size_t, size_t); diff --git a/socket.c b/socket.c index bd0fcb71..8c6057c 100644 --- a/socket.c +++ b/socket.c @@ -353,7 +353,12 @@ retry: case 0: case EINPROGRESS: case EINTR: +#ifdef EAGAIN + case EAGAIN: +#endif /* EAGAIN */ +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: +#endif /* EWOULDBLOCK */ break; default: SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket immedaitely"); @@ -478,7 +483,7 @@ static int SOCK_wait_for_ready(SocketClass *sock, BOOL output, int retry_count) tm.tv_sec = retry_count; tm.tv_usec = 0; } - ret = select((int) socket + 1, output ? NULL : &fds, output ? &fds : NULL, &except_fds, no_timeout ? NULL : &tm); + ret = select((int) sock->socket + 1, output ? NULL : &fds, output ? &fds : NULL, &except_fds, no_timeout ? NULL : &tm); gerrno = SOCK_ERRNO; } while (ret < 0 && EINTR == gerrno); if (retry_count < 0) @@ -520,7 +525,7 @@ static int SOCK_SSPI_send(SocketClass *self, const void *buffer, int len) /* * The stuff for SSL. */ -/* included in */ +/* included in #define SSL_ERROR_NONE 0 #define SSL_ERROR_SSL 1 #define SSL_ERROR_WANT_READ 2 @@ -530,7 +535,7 @@ static int SOCK_SSPI_send(SocketClass *self, const void *buffer, int len) #define SSL_ERROR_ZERO_RETURN 6 #define SSL_ERROR_WANT_CONNECT 7 #define SSL_ERROR_WANT_ACCEPT 8 - +*/ /* * recv more than 1 bytes using SSL. @@ -812,7 +817,12 @@ SOCK_flush_output(SocketClass *self) case EINTR: continue; break; +#ifdef EAGAIN + case EAGAIN: +#endif /* EAGAIN */ +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: +#endif /* EWOULDBLOCK */ retry_count++; if (SOCK_wait_for_ready(self, TRUE, retry_count) >= 0) continue; @@ -864,7 +874,12 @@ mylog("Lasterror=%d\n", gerrno); case EINTR: goto retry; break; +#ifdef EAGAIN + case EAGAIN: +#endif /* EAGAIN */ +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: +#endif /* EWOULDBLOCK */ retry_count++; if (SOCK_wait_for_ready(self, FALSE, retry_count) >= 0) goto retry; @@ -938,7 +953,12 @@ SOCK_put_next_byte(SocketClass *self, UCHAR next_byte) { case EINTR: continue; +#ifdef EAGAIN + case EAGAIN: +#endif /* EAGAIN */ +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: +#endif /* EWOULDBLOCK */ retry_count++; if (SOCK_wait_for_ready(self, TRUE, retry_count) >= 0) continue; diff --git a/socket.h b/socket.h index 3ca7071..8ac24f5 100644 --- a/socket.h +++ b/socket.h @@ -142,8 +142,10 @@ struct SocketClass_ /* SSL stuff */ void *ssl; /* libpq ssl */ #endif /* USE_SSL */ +#ifndef NOT_USE_LIBPQ void *pqconn; /* libpq PGConn */ BOOL via_libpq; /* using libpq library ? */ +#endif /* NOT_USE_LIBPQ */ char reverse; /* used to handle Postgres 6.2 protocol * (reverse byte order) */ diff --git a/statement.c b/statement.c index 472b346..571909f 100644 --- a/statement.c +++ b/statement.c @@ -389,6 +389,7 @@ SC_Constructor(ConnectionClass *conn) rv->ref_CC_error = FALSE; rv->lock_CC_for_rb = 0; rv->join_info = 0; + rv->curr_param_result = 0; SC_init_parse_method(rv); rv->lobj_fd = -1; @@ -1146,6 +1147,7 @@ SC_create_errorinfo(const StatementClass *self) Int4 errornum; size_t pos; BOOL resmsg = FALSE, detailmsg = FALSE, msgend = FALSE; + BOOL looponce, loopend; char msg[4096], *wmsg; char *ermsg = NULL, *sqlstate = NULL; PG_ErrorInfo *pgerror; @@ -1156,12 +1158,23 @@ SC_create_errorinfo(const StatementClass *self) if (errornum == 0) return NULL; + looponce = (SC_get_Result(self) != res); +mylog("looponce=%d\n", looponce); msg[0] = '\0'; - if (res) + for (loopend = FALSE; (NULL != res) && !loopend; res = res->next) { - if (res->sqlstate[0]) + if (looponce) + loopend = TRUE; + if ('\0' != res->sqlstate[0]) + { + if (NULL != sqlstate && strnicmp(res->sqlstate, "00", 2) == 0) + continue; sqlstate = res->sqlstate; - if (res->message) + if ('0' != sqlstate[0] || + '1' < sqlstate[1]) + loopend = TRUE; + } + if (NULL != res->message) { strncpy(msg, res->message, sizeof(msg)); detailmsg = resmsg = TRUE; @@ -1228,7 +1241,7 @@ SC_create_errorinfo(const StatementClass *self) strcpy(pgerror->sqlstate, conn->sqlstate); else { - EnvironmentClass *env = (EnvironmentClass *) conn->henv; + EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); errornum -= LOWEST_STMT_ERROR; if (errornum < 0 || @@ -1777,8 +1790,8 @@ SC_execute(StatementClass *self) if (issue_begin) CC_begin(conn); - res = SC_get_Result(self); -inolog("get_Result=%p\n", res); + for (res = SC_get_Result(self); NULL != res->next; res = res->next) ; +inolog("get_Result=%p %p %d\n", res, SC_get_Result(self), self->curr_param_result); if (!plan_name) plan_name = ""; if (!SendBindRequest(self, plan_name)) @@ -1793,10 +1806,10 @@ inolog("get_Result=%p\n", res); SC_set_error(self, STMT_EXEC_ERROR, "Execute request error", func); goto cleanup; } - if (!(res = SendSyncAndReceive(self, res, "bind_and_execute"))) + if (!(res = SendSyncAndReceive(self, self->curr_param_result ? res : NULL, "bind_and_execute"))) { if (SC_get_errornumber(self) <= 0) - SC_set_error(self, STMT_EXEC_ERROR, "Could not receive he response, communication down ??", func); + SC_set_error(self, STMT_EXEC_ERROR, "Could not receive the response, communication down ??", func); CC_on_abort(conn, CONN_DEAD); goto cleanup; } @@ -2012,14 +2025,18 @@ inolog("res->next=%p\n", tres); } if (!SC_get_Result(self)) SC_set_Result(self, res); - else if (res == SC_get_Result(self)) - ; else { QResultClass *last; - for (last = SC_get_Result(self); last->next; last = last->next) - ; - last->next = res; + + for (last = SC_get_Result(self); NULL != last->next; last = last->next) + { + if (last == res) + break; + } + if (last != res) + last->next = res; + self->curr_param_result = 1; } ipdopts = SC_get_IPDF(self); diff --git a/statement.h b/statement.h index 5293ae7..ef2582b 100644 --- a/statement.h +++ b/statement.h @@ -234,6 +234,7 @@ struct StatementClass_ char lock_CC_for_rb; /* lock CC for statement rollback ? */ char join_info; /* have joins ? */ char parse_method; /* parse_statement is forced or ? */ + char curr_param_result; /* current param result is set ? */ pgNAME cursor_name; char *plan_name; @@ -271,7 +272,7 @@ struct StatementClass_ }; #define SC_get_conn(a) (a->hdbc) -#define SC_init_Result(a) (a->result = a->curres = NULL, mylog("SC_init_Result(%x)", a)) +#define SC_init_Result(a) (a->result = a->curres = NULL, a->curr_param_result = 0, mylog("SC_init_Result(%x)", a)) #define SC_set_Result(a, b) \ do { \ if (b != a->result) \ @@ -279,6 +280,8 @@ do { \ mylog("SC_set_Result(%x, %x)", a, b); \ QR_Destructor(a->result); \ a->result = a->curres = b; \ + if (NULL != b) \ + a->curr_param_result = 1; \ } \ } while (0) #define SC_get_Result(a) (a->result) @@ -441,6 +444,7 @@ RETCODE SC_initialize_and_recycle(StatementClass *self); void SC_initialize_cols_info(StatementClass *self, BOOL DCdestroy, BOOL parseReset); int statement_type(const char *statement); char parse_statement(StatementClass *stmt, BOOL); +char parse_sqlsvr(StatementClass *stmt); SQLRETURN SC_set_SS_columnkey(StatementClass *stmt); Int4 SC_pre_execute(StatementClass *self); char SC_unbind_cols(StatementClass *self); diff --git a/version.h b/version.h index cfa66ec..3527820 100644 --- a/version.h +++ b/version.h @@ -9,9 +9,9 @@ #ifndef __VERSION_H__ #define __VERSION_H__ -#define POSTGRESDRIVERVERSION "08.03.0100" -#define POSTGRES_RESOURCE_VERSION "08.03.0100\0" -#define PG_DRVFILE_VERSION 8,3,01,00 -#define PG_BUILD_VERSION "200801290001" +#define POSTGRESDRIVERVERSION "08.03.0101" +#define POSTGRES_RESOURCE_VERSION "08.03.0101\0" +#define PG_DRVFILE_VERSION 8,3,01,01 +#define PG_BUILD_VERSION "200805020001" #endif diff --git a/win64.mak b/win64.mak index 98504cd..e874874 100755 --- a/win64.mak +++ b/win64.mak @@ -6,7 +6,7 @@ # # Configurations: Debug, Release # Build Types: ALL, CLEAN -# Usage: NMAKE /f win32_64.mak CFG=[Release | Debug] [ALL | CLEAN] +# Usage: NMAKE /f win64.mak CFG=[Release | Debug] [ALL | CLEAN] # # Comments: Created by Hiroshi Inoue, 2006-10-31 # @@ -34,7 +34,7 @@ CFG=Release !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f win32_64.mak CFG=[Release | Debug] [ALL | CLEAN] +!MESSAGE NMAKE /f win64.mak CFG=[Release | Debug] [ALL | CLEAN] !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -- 2.39.5