. Configure the combination of time.h and sys/time.h.
. Treat the tables in information_schema as system tables.
. Correct the precision of SQL_NUMERIC_STRUCT.
. Change the default max varchar size from 254 to 255.
. Reset the fields information properly in case of SQLMoreResults.
. Implement SQLDescribeParam() also in case of multi-command queries.
. Handle dollar-quotes more properly.
. Provide a make option to link dynamic multithread library.
. Set the default nullablity to TRUE.
. Parse command delimiters(;) more correctly.
. Use QR_get_value_backend_text() or QR_get_value_backend_int()
instead of QR_get_value_backend_row().
. Apply Parse statement or disallow premature properly.
. Reset current_schema cache in case 'set search_path ..' command
is issued.
*pfSqlType = ipdopts->parameters[ipar].SQLType;
else if (ipdopts->parameters[ipar].PGType)
*pfSqlType = pgtype_to_concise_type(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC);
+ else
+ {
+ ret = SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Unfortunatley couldn't get this paramater's info", func);
+ goto cleanup;
+ }
}
if (pcbParamDef)
}
else
{
- const char *sptr, *tag = NULL;
- ConnectionClass *conn = SC_get_conn(stmt);
- size_t taglen = 0;
- char tchar, bchar, escape_in_literal = '\0';
- char in_literal = FALSE, in_identifier = FALSE,
- in_dollar_quote = FALSE, in_escape = FALSE,
- multi = FALSE, del_found = FALSE;
- encoded_str encstr;
+ char multi = FALSE, proc_return = 0;
stmt->proc_return = 0;
- make_encoded_str(&encstr, conn, stmt->statement);
- for (sptr = stmt->statement, bchar = '\0'; *sptr; sptr++)
- {
- tchar = encoded_nextchar(&encstr);
- if (ENCODE_STATUS(encstr) != 0) /* multibyte char */
- {
- if ((UCHAR) tchar >= 0x80)
- bchar = tchar;
- continue;
- }
- if (!multi && del_found)
- {
- if (!isspace(tchar))
- multi = TRUE;
- }
- if (in_dollar_quote)
- {
- if (tchar == dollar_quote)
- {
- if (strncmp(sptr, tag, taglen) == 0)
- {
- in_dollar_quote = FALSE;
- tag = NULL;
- sptr += taglen;
- sptr--;
- encoded_position_shift(&encstr, taglen - 1);
- }
- }
- }
- else if (in_literal)
- {
- if (in_escape)
- in_escape = FALSE;
- else if (tchar == escape_in_literal)
- in_escape = TRUE;
- else if (tchar == literal_quote)
- in_literal = FALSE;
- }
- else if (in_identifier)
- {
- if (tchar == identifier_quote)
- in_identifier = FALSE;
- }
- else
- {
- if (tchar == '?')
- {
- if (0 == *pcpar && bchar == '{')
- stmt->proc_return = 1;
- (*pcpar)++;
- }
- else if (tchar == ';')
- del_found = TRUE;
- else if (tchar == dollar_quote)
- {
- char *dollar_next;
-
- in_dollar_quote = TRUE;
- tag = sptr;
- taglen = 0;
- if (dollar_next = strchr(sptr + 1, dollar_quote), NULL != dollar_next)
- {
- taglen = dollar_next - sptr + 1;
- sptr = dollar_next;
- encoded_position_shift(&encstr, taglen - 1);
- }
- }
- else if (tchar == literal_quote)
- {
- in_literal = TRUE;
- escape_in_literal = CC_get_escape(conn);
- if (!escape_in_literal)
- {
- if (LITERAL_EXT == sptr[-1])
- escape_in_literal = ESCAPE_IN_LITERAL;
- }
- }
- else if (tchar == identifier_quote)
- in_identifier = TRUE;
- if (!isspace(tchar))
- bchar = tchar;
- }
- }
+ SC_scanQueryAndCountParams(stmt->statement, SC_get_conn(stmt), NULL, pcpar, &multi, &proc_return);
stmt->num_params = *pcpar;
+ stmt->proc_return = proc_return;
stmt->multi_statement = multi;
+ if (multi)
+ SC_no_parse_tricky(stmt);
}
inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
return SQL_SUCCESS;
new_pdata = (PutDataClass *) realloc(self->pdata, sizeof(PutDataClass) * num_params);
if (!new_pdata)
{
- mylog("%s: unable to create %d new pdata from %d old pdata\n", func, num_params, self->allocated);
+ mylog("%s: unable to create new pdata of %d params(%d old pdata)\n", func, num_params, self->allocated);
self->pdata = NULL;
self->allocated = 0;
AC_LIBTOOL_DLOPEN
AC_PROG_LIBTOOL
-AC_CHECK_HEADERS([locale.h])
-AC_CHECK_HEADERS([sys/un.h])
+AC_CHECK_HEADERS(locale.h sys/un.h sys/time.h)
+AC_HEADER_TIME
AC_CHECK_TYPES(ssize_t)
PGAC_VAR_INT_TIMEZONE
#ifdef WIN32
extern int platformId;
#endif /* WIN32 */
+
/*
* IMPLEMENTATION CONNECTION CLASS
*/
+
+static void
+reset_current_schema(ConnectionClass *self)
+{
+ if (self->current_schema)
+ {
+ free(self->current_schema);
+ self->current_schema = NULL;
+ }
+}
+
ConnectionClass *
CC_Constructor()
{
free(self->server_encoding);
self->server_encoding = NULL;
}
- if (self->current_schema)
- {
- free(self->current_schema);
- self->current_schema = NULL;
- }
+ reset_current_schema(self);
/* Free cached table info */
if (self->col_info)
{
static char CC_initial_log(ConnectionClass *self, const char *func)
{
const ConnInfo *ci = &self->connInfo;
- char *encoding;
+ char *encoding, vermsg[128];
- qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
- POSTGRESDRIVERVERSION,
+ snprintf(vermsg, sizeof(vermsg), "Driver Version='%s,%s'"
+#ifdef WIN32
+ " linking"
+#ifdef _MT
+#ifdef _DLL
+ " dynamic"
+#else
+ " static"
+#endif /* _DLL */
+ " Multithread"
+#else
+ " Singlethread"
+#endif /* _MT */
+#ifdef NOT_USED
+#ifdef _DEBUG
+ " Debug"
+#else
+ " Release"
+#endif /* DEBUG */
+#endif /* NOT_USED */
+ " library"
+#endif /* WIN32 */
+ "\n", POSTGRESDRIVERVERSION, PG_BUILD_VERSION);
+ qlog(vermsg);
+ mylog(vermsg);
+ qlog("Global Options: fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
ci->drivers.fetch_max,
ci->drivers.socket_buffersize,
ci->drivers.unknown_sizes,
CONNLOCK_RELEASE(conn);
}
+static BOOL
+is_setting_search_path(const UCHAR* query)
+{
+ for (query += 4; *query; query++)
+ {
+ if (!isspace(*query))
+ {
+ if (strnicmp(query, "search_path", 11) == 0)
+ return TRUE;
+ query++;
+ while (*query && !isspace(*query))
+ query++;
+ }
+ }
+ return FALSE;
+}
+
/*
* The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
* the same existing QResultClass (this occurs when the tuple cache is depleted and
res->recent_processed_row_count = atoi(ptr + 1);
else
res->recent_processed_row_count = -1;
- if (!PROTOCOL_74(&(self->connInfo)))
+ if (PROTOCOL_74(&(self->connInfo)))
+ {
+ if (NULL != self->current_schema &&
+ strnicmp(cmdbuffer, "SET", 3) == 0)
+ {
+ if (is_setting_search_path(query))
+ reset_current_schema(self);
+ }
+ }
+ else
{
if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
CC_on_commit(self);
{
if (dot_exist)
ns->scale++;
- else
- ns->precision++;
+ ns->precision++;
calv[nlen++] = *wv;
}
}
BOOL ret;
ConnectionClass *conn = SC_get_conn(stmt);
QResultClass *res;
- char plan_name[32];
+ char plan_name[32], multi;
int func_cs_count = 0;
+ const char *orgquery, *srvquery;
+ Int4 endp1, endp2;
+ SQLSMALLINT num_pa = 0, num_p1, num_p2;
inolog("prep_params\n");
qb->flags |= FLGB_BUILDING_PREPARE_STATEMENT;
else
strcpy(plan_name, NULL_STRING);
- ret = SendParseRequest(stmt, plan_name, qb->query_statement);
- QB_Destructor(qb);
+ stmt->current_exec_param = 0;
+ multi = stmt->multi_statement;
+ if (multi > 0)
+ {
+ orgquery = stmt->statement;
+ SC_scanQueryAndCountParams(orgquery, conn, &endp1, &num_p1, NULL, NULL);
+ srvquery = qb->query_statement;
+ SC_scanQueryAndCountParams(srvquery, conn, &endp2, NULL, NULL, NULL);
+ mylog("%s:SendParseRequest for the first command length=%d(%d) num_p=%d\n", func, endp2, endp1, num_p1);
+ ret = SendParseRequest(stmt, plan_name, srvquery, endp2, num_p1);
+ }
+ else
+ ret = SendParseRequest(stmt, plan_name, qb->query_statement, SQL_NTS, -1);
if (!ret)
goto cleanup;
if (!SendDescribeRequest(stmt, plan_name))
goto cleanup;
}
SC_set_Result(stmt, res);
- if (QR_command_maybe_successful(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;
- else
- SC_set_error(stmt, STMT_EXEC_ERROR, "Error while preparing parameters", func);
+ goto cleanup;
+ }
+ while (multi > 0)
+ {
+ orgquery += (endp1 + 1);
+ srvquery += (endp2 + 1);
+ num_pa += num_p1;
+ SC_scanQueryAndCountParams(orgquery, conn, &endp1, &num_p1, &multi, NULL);
+ SC_scanQueryAndCountParams(srvquery, conn, &endp2, &num_p2, NULL, NULL);
+ mylog("%s:SendParseRequest for the subsequent command length=%d(%d) num_p=%d\n", func, endp2, endp1, num_p1);
+ if (num_p2 > 0)
+ {
+ 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))
+ goto cleanup;
+ if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
+ {
+ SC_set_error(stmt, STMT_EXEC_ERROR, "commnication error while preapreand_describe", func);
+ CC_on_abort(conn, CONN_DEAD);
+ goto cleanup;
+ }
+ QR_Destructor(res);
+ }
+ }
+ retval = SQL_SUCCESS;
cleanup:
#undef return
CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
+ stmt->current_exec_param = -1;
+ QB_Destructor(qb);
return retval;
}
qp->declare_pos = 0;
}
+Int4 findTag(const char *tag, char dollar_quote, int ccsc)
+{
+ Int4 taglen = 0;
+ encoded_str encstr;
+ char tchar;
+ const char *sptr;
+
+ encoded_str_constr(&encstr, ccsc, tag + 1);
+ for (sptr = tag + 1; *sptr; sptr++)
+ {
+ tchar = encoded_nextchar(&encstr);
+ if (ENCODE_STATUS(encstr) != 0)
+ continue;
+ if (dollar_quote == tchar)
+ {
+ taglen = sptr - tag + 1;
+ break;
+ }
+ if (isspace(tchar))
+ break;
+ }
+ return taglen;
+}
+
static int
inner_process_tokens(QueryParse *qp, QueryBuild *qb)
{
{
if (oldchar == dollar_quote)
{
- char *next_dollar;
-
- qp->in_literal = TRUE;
- qp->in_dollar_quote = TRUE;
- qp->dollar_tag = F_OldPtr(qp);
- qp->taglen = 1;
- if (next_dollar = strchr(F_OldPtr(qp) + 1, dollar_quote), NULL != next_dollar)
+ qp->taglen = findTag(F_OldPtr(qp), dollar_quote, qp->encstr.ccsc);
+ if (qp->taglen > 0)
{
- qp->taglen = next_dollar - F_OldPtr(qp) + 1;
+ qp->in_literal = TRUE;
+ qp->in_dollar_quote = TRUE;
+ qp->dollar_tag = F_OldPtr(qp);
CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
qp->opos += (qp->taglen - 1);
return SQL_SUCCESS;
}
else if (oldchar == ';')
{
+ /*
+ * can't parse multiple statement using protocol V3.
+ * reset the dollar number here in case it is divided
+ * to parse.
+ */
+ qb->dollar_number = 0;
if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK))
{
const char *vp = &(qp->statement[qp->opos + 1]);
static BOOL
ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
{
- static const int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 29, 32, 34, 37, 39};
+ static const int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
Int4 i, j, k, ival, vlen, len, newlen;
UCHAR calv[40];
const UCHAR *val = (const UCHAR *) ns->val;
SQLLEN pg_hex2bin(const UCHAR *in, UCHAR *out, SQLLEN len);
int convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType,
PTR rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue);
+Int4 findTag(const char *str, char dollar_quote, int ccsc);
#ifdef __cplusplus
}
if (reuse)
FI_Destructor(&self, 1, FALSE);
memset(self, 0, sizeof(FIELD_INFO));
+ self->nullable = TRUE;
}
void FI_Destructor(FIELD_INFO **fi, int count, BOOL freeFI)
{
if (ODBCINST_INI == fileName && NULL == sectionName)
sectionName = DBMS_NAME;
- sprintf(tmp, "%d", comval->fetch_max);
- SQLWritePrivateProfileString(sectionName,
- INI_FETCH, tmp, fileName);
-
sprintf(tmp, "%d", comval->commlog);
SQLWritePrivateProfileString(sectionName,
INI_COMMLOG, tmp, fileName);
SQLWritePrivateProfileString(sectionName,
INI_DEBUG, tmp, fileName);
+ sprintf(tmp, "%d", comval->fetch_max);
+ SQLWritePrivateProfileString(sectionName,
+ INI_FETCH, tmp, fileName);
+
+ if (stricmp(ODBCINST_INI, fileName) == 0)
+ return;
+
+ sprintf(tmp, "%d", comval->fetch_max);
+ SQLWritePrivateProfileString(sectionName,
+ INI_FETCH, tmp, fileName);
+
sprintf(tmp, "%d", comval->disable_optimizer);
SQLWritePrivateProfileString(sectionName,
INI_OPTIMIZER, tmp, fileName);
}
if (stmt->multi_statement < 0)
PGAPI_NumParams((StatementClass *) stmt, &num_params);
- if (stmt->multi_statement > 0) /* server-side prepare mechanism coundn' handle multi statement */
- return PREPARE_BY_THE_DRIVER;
+ if (stmt->multi_statement > 0) /* would divide the query into multiple commands and apply V3 parse requests for each of them */
+ ret = PARSE_REQ_FOR_INFO;
else if (PROTOCOL_74(ci))
{
if (STMT_TYPE_SELECT == stmt->statement_type)
{
if (ci->drivers.use_declarefetch)
- /* ret = PREPARE_BY_THE_DRIVER; */
return PARSE_REQ_FOR_INFO;
else if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)
ret = PARSE_REQ_FOR_INFO;
/*
* Dummy exection to get the column info.
*/
- if (stmt->inaccurate_result && conn->connInfo.disallow_premature)
+ if (stmt->inaccurate_result && SC_is_parse_tricky(stmt))
{
BOOL in_trans = CC_is_in_trans(conn);
BOOL issued_begin = FALSE,
if (estmt->data_at_exec == 0)
{
BOOL exec_end;
+ UWORD flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0;
retval = Exec_with_parameters_resolved(estmt, &exec_end);
if (exec_end)
retval = dequeueNeedDataCallback(retval, stmt);
goto cleanup;
}
- if (retval = PGAPI_Execute(estmt, 0), SQL_NEED_DATA != retval)
+ if (retval = PGAPI_Execute(estmt, flag), SQL_NEED_DATA != retval)
{
goto cleanup;
}
systable = FALSE;
if (!atoi(ci->show_system_tables))
{
- if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
+ if (conn->schema_support)
+ {
+ if (stricmp(table_owner, "pg_catalog") == 0 ||
+ stricmp(table_owner, "pg_toast") == 0 ||
+ strnicmp(table_owner, "pg_temp_", 8) == 0 ||
+ stricmp(table_owner, "information_schema") == 0)
+ systable = TRUE;
+ }
+ else if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
systable = TRUE;
else
snprintf(cmd, sizeof(cmd), "select pg_get_indexdef(%u, %d, true)", ioid, i);
res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, stmt);
if (QR_command_maybe_successful(res))
- set_tuplefield_string(&tuple[STATS_COLUMN_NAME], QR_get_value_backend_row(res, 0, 0));
+ set_tuplefield_string(&tuple[STATS_COLUMN_NAME], QR_get_value_backend_text(res, 0, 0));
QR_Destructor(res);
}
else
if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, flag, NULL), QR_command_maybe_successful(res))
{
if (QR_get_num_cached_tuples(res) > 0)
- conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
+ conn->server_encoding = strdup(QR_get_value_backend_text(res, 0, 0));
}
QR_Destructor(res);
res = NULL;
{
if (QR_get_num_cached_tuples(res) > 0)
{
- strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
+ strcpy(saveattnum, QR_get_value_backend_text(res, 0, 0));
}
else
continueExec = FALSE;
{
if (QR_get_num_cached_tuples(res) > 0)
{
- ret = strdup(QR_get_value_backend_row(res, 0, 0));
+ ret = strdup(QR_get_value_backend_text(res, 0, 0));
*nameAlloced = TRUE;
}
}
for (i = 0, poid = 0; i < tcount; i++)
{
if (conn->schema_support)
- schema_name = GET_SCHEMA_NAME(QR_get_value_backend_row(tres, i, 5));
+ schema_name = GET_SCHEMA_NAME(QR_get_value_backend_text(tres, i, 5));
else
schema_name = NULL;
- procname = QR_get_value_backend_row(tres, i, 0);
- retset = QR_get_value_backend_row(tres, i, 1);
- pgtype = atoi(QR_get_value_backend_row(tres, i, 2));
+ procname = QR_get_value_backend_text(tres, i, 0);
+ retset = QR_get_value_backend_text(tres, i, 1);
+ pgtype = QR_get_value_backend_int(tres, i, 2, NULL);
bRetset = retset && (retset[0] == 't' || retset[0] == 'y');
newpoid = 0;
if (poid_pos >= 0)
- newpoid = atoi(QR_get_value_backend_row(tres, i, poid_pos));
+ newpoid = QR_get_value_backend_int(tres, i, poid_pos, NULL);
mylog("newpoid=%d\n", newpoid);
atttypid = NULL;
if (attid_pos >= 0)
{
- atttypid = QR_get_value_backend_row(tres, i, attid_pos);
+ atttypid = QR_get_value_backend_text(tres, i, attid_pos);
mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
}
if (poid == 0 || newpoid != poid)
{
#ifdef DISPLAY_ARGNAME /* !! named parameter is unavailable !! */
if (PG_VERSION_GE(conn, 8.0))
- proargnames = QR_get_value_backend_row(tres, i, ext_pos);
+ proargnames = QR_get_value_backend_text(tres, i, ext_pos);
#endif /* DISPLAY_ARGNAME */
if (PG_VERSION_GE(conn, 8.1))
- proargmodes = QR_get_value_backend_row(tres, i, ext_pos + 1);
+ proargmodes = QR_get_value_backend_text(tres, i, ext_pos + 1);
}
/* RETURN_VALUE info */
if (0 != pgtype && PG_TYPE_VOID != pgtype && !bRetset && !atttypid && !proargmodes)
paramcount++;
}
paramcount++;
- params = QR_get_value_backend_row(tres, i, ext_pos + 2);
+ params = QR_get_value_backend_text(tres, i, ext_pos + 2);
if ('{' == *proargmodes)
proargmodes++;
if ('{' == *params)
}
else
{
- paramcount = atoi(QR_get_value_backend_row(tres, i, 3));
- params = QR_get_value_backend_row(tres, i, 4);
+ paramcount = QR_get_value_backend_int(tres, i, 3, NULL);
+ params = QR_get_value_backend_text(tres, i, 4);
}
if (proargnames)
{
else
{
typid = atoi(atttypid);
- attname = QR_get_value_backend_row(tres, i, attname_pos);
+ attname = QR_get_value_backend_text(tres, i, attname_pos);
}
tuple = QR_AddNew(res);
set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
if (user[0])
for (i = 0; i < usercount; i++)
{
- if (strcmp(QR_get_value_backend_row(allures, i, 0), user) == 0)
+ if (strcmp(QR_get_value_backend_text(allures, i, 0), user) == 0)
{
addcnt += usracl_auth(useracl[i], auth);
break;
for (i = 0; i < tablecount; i++)
{
memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
- acl = (char *) QR_get_value_backend_row(wres, i, 2);
+ acl = (char *) QR_get_value_backend_text(wres, i, 2);
if (acl && acl[0] == '{')
user = acl + 1;
else
snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
if (gres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(gres))
{
- grolist = QR_get_value_backend_row(gres, 0, 0);
+ grolist = QR_get_value_backend_text(gres, 0, 0);
if (grolist && grolist[0] == '{')
{
for (uid = grolist + 1; *uid;)
mylog("guid=%s\n", uid);
for (i = 0; i < usercount; i++)
{
- if (strcmp(QR_get_value_backend_row(allures, i, 1), uid) == 0)
- useracl_upd(useracl, allures, QR_get_value_backend_row(allures, i, 0), auth);
+ if (strcmp(QR_get_value_backend_text(allures, i, 1), uid) == 0)
+ useracl_upd(useracl, allures, QR_get_value_backend_text(allures, i, 0), auth);
}
uid = delm + 1;
}
break;
user = delim + 1;
}
- reln = QR_get_value_backend_row(wres, i, 0);
- owner = QR_get_value_backend_row(wres, i, 1);
+ reln = QR_get_value_backend_text(wres, i, 0);
+ owner = QR_get_value_backend_text(wres, i, 1);
if (conn->schema_support)
- schnm = QR_get_value_backend_row(wres, i, 3);
+ schnm = QR_get_value_backend_text(wres, i, 3);
/* The owner has all privileges */
useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
for (j = 0; j < usercount; j++)
{
- user = QR_get_value_backend_row(allures, j, 0);
- su = (strcmp(QR_get_value_backend_row(allures, j, 2), "t") == 0);
+ user = QR_get_value_backend_text(allures, j, 0);
+ su = (strcmp(QR_get_value_backend_text(allures, j, 2), "t") == 0);
sys = (strcmp(user, owner) == 0);
/* Super user has all privileges */
if (su)
if (!qlog_on) return;
ENTER_QLOG_CS;
+#ifdef LOGGING_PROCESS_TIME
+ if (!start_time)
+ start_time = timeGetTime();
+#endif /* LOGGING_PROCESS_TIME */
va_start(args, fmt);
if (!QLOGFP)
}
if (QLOGFP)
+ {
+#ifdef LOGGING_PROCESS_TIME
+ DWORD proc_time = timeGetTime() - start_time;
+ fprintf(QLOGFP, "[%d.%03d]", proc_time / 1000, proc_time % 1000);
+#endif /* LOGGING_PROCESS_TIME */
vfprintf(QLOGFP, fmt, args);
+ }
va_end(args);
LEAVE_QLOG_CS;
inolog("getColInfo non-manual result\n");
fi->dquote = TRUE;
- STR_TO_NAME(fi->column_name, QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME));
+ STR_TO_NAME(fi->column_name, QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME));
- fi->columntype = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_FIELD_TYPE));
- fi->column_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_PRECISION));
- fi->length = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_LENGTH));
- if (str = QR_get_value_backend_row(col_info->result, k, COLUMNS_SCALE), str)
+ fi->columntype = (OID) QR_get_value_backend_int(col_info->result, k, COLUMNS_FIELD_TYPE, NULL);
+ fi->column_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_PRECISION, NULL);
+ fi->length = QR_get_value_backend_int(col_info->result, k, COLUMNS_LENGTH, NULL);
+ if (str = QR_get_value_backend_text(col_info->result, k, COLUMNS_SCALE), str)
fi->decimal_digits = atoi(str);
else
fi->decimal_digits = -1;
- fi->nullable = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_NULLABLE));
- fi->display_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_DISPLAY_SIZE));
- fi->auto_increment = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_AUTO_INCREMENT));
+ fi->nullable = QR_get_value_backend_int(col_info->result, k, COLUMNS_NULLABLE, NULL);
+ fi->display_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_DISPLAY_SIZE, NULL);
+ fi->auto_increment = QR_get_value_backend_int(col_info->result, k, COLUMNS_AUTO_INCREMENT, NULL);
}
{
int k,
cmp, attnum;
- char *col;
+ const char *col;
inolog("searchColInfo num_cols=%d col=%s\n", QR_get_num_cached_tuples(col_info->result), PRINT_NAME(fi->column_name));
if (fi->attnum < 0)
{
if (fi->attnum > 0)
{
- attnum = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_PHYSICAL_NUMBER));
+ attnum = QR_get_value_backend_int(col_info->result, k, COLUMNS_PHYSICAL_NUMBER, NULL);
inolog("searchColInfo %d attnum=%d\n", k, attnum);
if (attnum == fi->attnum)
{
}
else if (NAME_IS_VALID(fi->column_name))
{
- col = QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME);
+ col = QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME);
inolog("searchColInfo %d col=%s\n", k, col);
if (fi->dquote)
cmp = strcmp(col, GET_NAME(fi->column_name));
stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
if (1 == QR_get_num_total_tuples(res))
{
- char *value = QR_get_value_backend_row(res, 0, 0);
+ const char *value = QR_get_value_backend_text(res, 0, 0);
if (value && ('f' == *value || '0' == *value))
{
hasoids = FALSE;
STR_TO_NAME(ti->bestqual, query);
}
TI_set_hasoids_checked(ti);
- ti->table_oid = strtoul(QR_get_value_backend_row(res, 0, 1), NULL, 10);
+ ti->table_oid = (OID) strtoul(QR_get_value_backend_text(res, 0, 1), NULL, 10);
}
QR_Destructor(res);
res = NULL;
if (QR_command_maybe_successful(res) && QR_get_num_total_tuples(res) > 0)
{
foundKey = TRUE;
- STR_TO_NAME(ti->bestitem, QR_get_value_backend_row(res, 0, 0));
+ STR_TO_NAME(ti->bestitem, QR_get_value_backend_text(res, 0, 0));
sprintf(query, "\"%s\" = %%", SAFE_NAME(ti->bestitem));
- if (PG_TYPE_INT4 == atoi(QR_get_value_backend_row(res, 0, 1)))
+ if (PG_TYPE_INT4 == (OID) QR_get_value_backend_int(res, 0, 1, NULL))
strcat(query, "d");
else
strcat(query, "u");
irdflds->nfields = (UInt4) numFields;
}
+void SC_initialize_cols_info(StatementClass *stmt, BOOL DCdestroy, BOOL parseReset)
+{
+ IRDFields *irdflds = SC_get_IRDF(stmt);
+
+ /* Free the parsed table information */
+ if (stmt->ti)
+ {
+ TI_Destructor(stmt->ti, stmt->ntab);
+ free(stmt->ti);
+ stmt->ti = NULL;
+ }
+ stmt->ntab = 0;
+ if (DCdestroy) /* Free the parsed field information */
+ DC_Destructor((DescriptorClass *) SC_get_IRD(stmt));
+ else
+ setNumFields(irdflds, 0);
+ if (parseReset)
+ {
+ stmt->parse_status = STMT_PARSE_NONE;
+ stmt->updatable = FALSE;
+ }
+}
+
static BOOL allocateFields(IRDFields *irdflds, size_t sizeRequested)
{
FIELD_INFO **fi = irdflds->fi;
if (QR_get_num_total_tuples(res) == 1)
{
tblFound = TRUE;
- STR_TO_NAME(*schema_name, QR_get_value_backend_row(res, 0, 0));
+ STR_TO_NAME(*schema_name, QR_get_value_backend_text(res, 0, 0));
}
}
QR_Destructor(res);
if (res && QR_get_num_cached_tuples(res) > 0)
{
if (!greloid)
- greloid = strtoul(QR_get_value_backend_row(res, 0, COLUMNS_TABLE_OID), NULL, 10);
+ 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_row(res, 0, COLUMNS_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_row(res, 0, COLUMNS_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);
/*
conn->ntables++;
if (res && QR_get_num_cached_tuples(res) > 0)
-inolog("oid item == %s\n", QR_get_value_backend_row(res, 0, 3));
+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 */
if (res && QR_get_num_cached_tuples(res) > 0)
{
if (!greloid)
- greloid = strtoul(QR_get_value_backend_row(res, 0, COLUMNS_TABLE_OID), NULL, 10);
+ 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_row(res, 0, COLUMNS_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_row(res, 0, COLUMNS_TABLE_NAME));
+ QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME));
}
inolog("#1 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid);
if (colatt /* SQLColAttribute case */
ti = stmt->ti;
allocated_size = irdflds->allocated;
- setNumFields(irdflds, 0);
- if (stmt->ntab > 0)
- {
- TI_Destructor(stmt->ti, stmt->ntab);
- free(stmt->ti);
- stmt->ti = NULL;
- stmt->ntab = 0;
- }
+ SC_initialize_cols_info(stmt, FALSE, TRUE);
stmt->from_pos = -1;
stmt->where_pos = -1;
#define return DONT_CALL_RETURN_FROM_HERE???
mylog("*** setting expression\n");
} /* in_select end */
- if (in_from)
+ if (in_from || in_where)
{
- if (token[0] == ';')
+ if (token[0] == ';') /* end of the first command */
{
- in_from = FALSE;
+ in_select = in_from = in_where = in_table = FALSE;
break;
}
+ }
+ if (in_from)
+ {
switch (token[0])
{
case '\0':
#undef return
if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
{
- setNumFields(irdflds, 0);
- TI_Destructor(stmt->ti, stmt->ntab);
- free(stmt->ti);
- stmt->ti = NULL;
- stmt->ntab = 0;
+ SC_initialize_cols_info(stmt, FALSE, FALSE);
parse = FALSE;
}
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: psqlodbc.h,v 1.115 2006/11/14 15:29:26 hinoue Exp $
+ * $Id: psqlodbc.h,v 1.116 2007/03/04 10:41:49 hinoue Exp $
*
*/
#define TEXT_FIELD_SIZE 8190 /* size of text fields
* (not including null
* term) */
-#define MAX_VARCHAR_SIZE 254 /* maximum size of a varchar (not
+#define MAX_VARCHAR_SIZE 255 /* maximum size of a varchar (not
* including null term) */
#define PG_NUMERIC_MAX_PRECISION 1000
/* These functions are for retrieving data from the qresult */
#define QR_get_value_backend(self, fieldno) (self->tupleField[fieldno].value)
#define QR_get_value_backend_row(self, tupleno, fieldno) ((self->backend_tuples + (tupleno * self->num_fields))[fieldno].value)
+#define QR_get_value_backend_text(self, tupleno, fieldno) QR_get_value_backend_row(self, tupleno, fieldno)
+#define QR_get_value_backend_int(self, tupleno, fieldno, isNull) atoi(QR_get_value_backend_row(self, tupleno, fieldno))
/* These functions are used by both manual and backend results */
#define QR_NumResultCols(self) (CI_get_num_fields(self->fields))
goto cleanup;
}
parse_ok = FALSE;
- if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+ if (!stmt->catalog_result && SC_is_parse_forced(stmt) && stmt->statement_type == STMT_TYPE_SELECT)
{
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
{
fi = NULL;
if (icol < irdflds->nfields && irdflds->fi)
fi = irdflds->fi[icol];
- if (!FI_is_applicable(fi) && !stmt->catalog_result && ci->drivers.parse && STMT_TYPE_SELECT == stmt->statement_type)
+ if (!FI_is_applicable(fi) && !stmt->catalog_result && SC_is_parse_forced(stmt) && STMT_TYPE_SELECT == stmt->statement_type)
{
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
{
if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
unknown_sizes = UNKNOWNS_AS_MAX;
- if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+ if (!stmt->catalog_result && SC_is_parse_forced(stmt) && stmt->statement_type == STMT_TYPE_SELECT)
{
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
{
SC_set_Curres(stmt, res->next);
if (res = SC_get_Curres(stmt), res)
{
+ SQLSMALLINT num_p;
+
+ if (stmt->multi_statement < 0)
+ PGAPI_NumParams(stmt, &num_p);
+ if (stmt->multi_statement > 0)
+ {
+ const char *cmdstr;
+
+ SC_initialize_cols_info(stmt, FALSE, TRUE);
+ stmt->statement_type = STMT_TYPE_UNKNOWN;
+ if (cmdstr = QR_get_command(res), NULL != cmdstr)
+ stmt->statement_type = statement_type(cmdstr);
+ stmt->join_info = 0;
+ SC_clear_parse_method(stmt);
+ }
stmt->diag_row_count = res->recent_processed_row_count;
SC_set_rowset_start(stmt, -1, FALSE);
stmt->currTuple = -1;
mylog("selstr=%s\n", selstr);
qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, stmt);
+#ifdef NOT_USED
+if (qres)
+{
+int i, j;
+TupleField *tuple = qres->backend_tuples;
+mylog("%s qres=%p backend_tuples=%p\n", func, qres, tuple);
+for (i = 0; i < QR_get_num_cached_tuples(qres); i++)
+for (j = 0; j < qres->num_fields; j++, tuple++)
+mylog("tuple[%d,%d]=(%d,%p)\n", i, j, tuple->len, tuple->value);
+QR_free_memory(qres);
+}
+#endif /* NOT_USED */
cleanup:
free(selstr);
return qres;
}
/* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
}
+#ifdef NOT_USED
+mylog("about to QR_Destructor %p\n", qres);
+#endif /* NOT_USED */
QR_Destructor(qres);
return ret;
}
#ifndef WIN32
#include <stdlib.h>
#include <string.h> /* for memset */
-#if defined(TM_IN_SYS_TIME)
+#ifdef TIME_WITH_SYS_TIME
#include <sys/time.h>
-#else
#include <time.h>
-#endif /* defined(TM_IN_SYS_TIME) */
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
#else
#include <time.h>
+#endif /* HAVE_SYS_TIME_H */
+#endif /* TIME_WITH__SYS_TIME */
#endif /* WIN32 */
extern GLOBAL_VALUES globals;
void
-SOCK_put_n_char(SocketClass *self, char *buffer, Int4 len)
+SOCK_put_n_char(SocketClass *self, const char *buffer, Int4 len)
{
int lf;
char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout);
int SOCK_get_id(SocketClass *self);
void SOCK_get_n_char(SocketClass *self, char *buffer, Int4 len);
-void SOCK_put_n_char(SocketClass *self, char *buffer, Int4 len);
+void SOCK_put_n_char(SocketClass *self, const char *buffer, Int4 len);
BOOL SOCK_get_string(SocketClass *self, char *buffer, Int4 bufsize);
void SOCK_put_string(SocketClass *self, const char *string);
int SOCK_get_int(SocketClass *self, short len);
#include "bind.h"
#include "connection.h"
+#include "multibyte.h"
#include "qresult.h"
#include "convert.h"
#include "environ.h"
if (!conn->connInfo.use_server_side_prepare)
self->discard_output_params = 1;
}
+
+static void SC_init_parse_method(StatementClass *self)
+{
+ ConnectionClass *conn = SC_get_conn(self);
+
+ self->parse_method = 0;
+ if (!conn) return;
+ if (self->catalog_result) return;
+ if (conn->connInfo.drivers.parse)
+ SC_set_parse_forced(self);
+ if (self->multi_statement <= 0 && conn->connInfo.disallow_premature)
+ SC_set_parse_tricky(self);
+}
+
StatementClass *
SC_Constructor(ConnectionClass *conn)
{
rv->ref_CC_error = FALSE;
rv->lock_CC_for_rb = 0;
rv->join_info = 0;
+ SC_init_parse_method(rv);
rv->lobj_fd = -1;
INIT_NAME(rv->cursor_name);
SC_initialize_stmts(self, TRUE);
/* Free the parsed table information */
- if (self->ti)
- {
- TI_Destructor(self->ti, self->ntab);
-
- free(self->ti);
- self->ti = NULL;
- }
+ SC_initialize_cols_info(self, FALSE, TRUE);
NULL_THE_NAME(self->cursor_name);
/* Free the parsed field information */
RETCODE
SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
{
+ ConnectionClass *conn = SC_get_conn(self);
+
if (self->lock_CC_for_rb > 0)
{
- ConnectionClass *conn = SC_get_conn(self);
-
while (self->lock_CC_for_rb > 0)
{
LEAVE_CONN_CS(conn);
self->num_params = -1; /* unknown */
self->proc_return = -1; /* unknown */
self->join_info = 0;
+ SC_init_parse_method(self);
SC_init_discard_output_params(self);
}
if (self->stmt_with_params)
*/
if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
{
- if (SC_is_pre_executable(self) && !conn->connInfo.disallow_premature)
+ if (SC_is_pre_executable(self) && !SC_is_parse_tricky(self))
CC_abort(conn);
}
break;
{
case NOT_YET_PREPARED:
case ONCE_DESCRIBED:
- /* Free the parsed table information */
- if (self->ti)
- {
- TI_Destructor(self->ti, self->ntab);
- free(self->ti);
- self->ti = NULL;
- self->ntab = 0;
- }
- /* Free the parsed field information */
- DC_Destructor((DescriptorClass *) SC_get_IRD(self));
+ /* Free the parsed table/field information */
+ SC_initialize_cols_info(self, TRUE, TRUE);
inolog("SC_clear_parse_status\n");
SC_clear_parse_status(self, conn);
- self->updatable = FALSE;
break;
}
return TRUE;
}
+/*
+ * Scan the query wholly or partially (if specifed next_cmd).
+ * Also count the number of parameters respectviely.
+ */
+void
+SC_scanQueryAndCountParams(const char *query, const ConnectionClass *conn,
+ Int4 *next_cmd, SQLSMALLINT * pcpar,
+ char *multi_st, char *proc_return)
+{
+ CSTR func = "SC_scanQueryAndCountParams";
+ char literal_quote = LITERAL_QUOTE, identifier_quote = IDENTIFIER_QUOTE, dollar_quote = DOLLAR_QUOTE;
+ const char *sptr, *tstr, *tag = NULL;
+ size_t taglen = 0;
+ char tchar, bchar, escape_in_literal = '\0';
+ char in_literal = FALSE, in_identifier = FALSE,
+ in_dollar_quote = FALSE, in_escape = FALSE,
+ del_found = FALSE, multi = FALSE;
+ SQLSMALLINT num_p;
+ encoded_str encstr;
+
+ mylog("%s: entering...\n", func);
+ num_p = 0;
+ if (proc_return)
+ *proc_return = 0;
+ if (next_cmd)
+ *next_cmd = -1;
+ tstr = query;
+ make_encoded_str(&encstr, conn, tstr);
+ for (sptr = tstr, bchar = '\0'; *sptr; sptr++)
+ {
+ tchar = encoded_nextchar(&encstr);
+ if (ENCODE_STATUS(encstr) != 0) /* multibyte char */
+ {
+ if ((UCHAR) tchar >= 0x80)
+ bchar = tchar;
+ continue;
+ }
+ if (!multi && del_found)
+ {
+ if (!isspace(tchar))
+ {
+ multi = TRUE;
+ if (next_cmd)
+ break;
+ }
+ }
+ if (in_dollar_quote)
+ {
+ if (tchar == dollar_quote)
+ {
+ if (strncmp(sptr, tag, taglen) == 0)
+ {
+ in_dollar_quote = FALSE;
+ tag = NULL;
+ sptr += taglen;
+ sptr--;
+ encoded_position_shift(&encstr, taglen - 1);
+ }
+ }
+ }
+ else if (in_literal)
+ {
+ if (in_escape)
+ in_escape = FALSE;
+ else if (tchar == escape_in_literal)
+ in_escape = TRUE;
+ else if (tchar == literal_quote)
+ in_literal = FALSE;
+ }
+ else if (in_identifier)
+ {
+ if (tchar == identifier_quote)
+ in_identifier = FALSE;
+ }
+ else
+ {
+ if (tchar == '?')
+ {
+ if (0 == num_p && bchar == '{')
+ {
+ if (proc_return)
+ *proc_return = 1;
+ }
+ num_p++;
+ }
+ else if (tchar == ';')
+ {
+ del_found = TRUE;
+ if (next_cmd)
+ *next_cmd = sptr - query;
+ }
+ else if (tchar == dollar_quote)
+ {
+ taglen = findTag(sptr, dollar_quote, encstr.ccsc);
+ if (taglen > 0)
+ {
+ in_dollar_quote = TRUE;
+ tag = sptr;
+ sptr += (taglen - 1);
+ encoded_position_shift(&encstr, taglen - 1);
+ }
+ else
+ num_p++;
+ }
+ else if (tchar == literal_quote)
+ {
+ in_literal = TRUE;
+ escape_in_literal = CC_get_escape(conn);
+ if (!escape_in_literal)
+ {
+ if (LITERAL_EXT == sptr[-1])
+ escape_in_literal = ESCAPE_IN_LITERAL;
+ }
+ }
+ else if (tchar == identifier_quote)
+ in_identifier = TRUE;
+ if (!isspace(tchar))
+ bchar = tchar;
+ }
+ }
+ if (pcpar)
+ *pcpar = num_p;
+ if (multi_st)
+ *multi_st = multi;
+}
/*
* Pre-execute a statement (for SQLPrepare/SQLDescribeCol)
{ STMT_ROW_VERSION_CHANGED, "01001", "01001" }, /* data changed */
{ STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" },
{ STMT_TRUNCATED, "01004", "01004" }, /* data truncated */
- { STMT_INFO_ONLY, "00000", "00000" }, /* just information that is returned, no error */
+ { STMT_INFO_ONLY, "00000", "00000" }, /* just an information that is returned, no error */
{ STMT_OK, "00000", "00000" }, /* OK */
{ STMT_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
{
apara = apdopts->parameters + i;
ret = PGAPI_GetData(hstmt, gidx + 1, apara->CType, apara->buffer + offset, apara->buflen, apara->used ? LENADDR_SHIFT(apara->used, offset) : NULL);
- if (ret != SQL_SUCCESS)
+ if (SQL_SUCCESS != ret && SQL_SUCCESS_WITH_INFO != ret)
{
SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.", func);
break;
/* self->status = STMT_FINISHED; */
if (SC_get_errornumber(self) == STMT_OK)
return SQL_SUCCESS;
- else if (SC_get_errornumber(self) == STMT_INFO_ONLY)
+ else if (SC_get_errornumber(self) < STMT_OK)
return SQL_SUCCESS_WITH_INFO;
else
{
Int4 response_length;
UInt4 oid;
int num_p, num_io_params;
- int i;
+ int i, pidx;
Int2 num_discard_params, paramType;
BOOL rcvend = FALSE, msg_truncated;
char msgbuffer[ERROR_MSG_LENGTH + 1];
num_discard_params = stmt->proc_return;
if (num_p + num_discard_params != (int) stmt->num_params)
{
- mylog("ParamInfo unmatch num_params=%d! info=%d+discard=%d\n", stmt->num_params, num_p, num_discard_params);
- stmt->num_params = (Int2) num_p + num_discard_params;
+ mylog("ParamInfo unmatch num_params(=%d) != info(=%d)+discard(=%d)\n", stmt->num_params, num_p, num_discard_params);
+ /* stmt->num_params = (Int2) num_p + num_discard_params; it's possible in case of multi command queries */
}
ipdopts = SC_get_IPDF(stmt);
extend_iparameter_bindings(ipdopts, stmt->num_params);
+#ifdef NOT_USED
if (stmt->discard_output_params)
{
- for (i = stmt->proc_return; i < stmt->num_params; i++)
+ for (i = 0, pidx = stmt->proc_return; i < num_p && pidx < stmt->num_params; pidx++)
{
- paramType = ipdopts->parameters[i].paramType;
+ paramType = ipdopts->parameters[pidx].paramType;
if (SQL_PARAM_OUTPUT == paramType)
+ {
+ i++;
continue;
+ }
oid = SOCK_get_int(sock, 4);
- ipdopts->parameters[i].PGType = oid;
+ ipdopts->parameters[pidx].PGType = oid;
}
}
else
{
- for (i = 0; i < num_p; i++)
+ for (i = 0, pidx = stmt->proc_return; i < num_p; i++, pidx++)
{
- paramType = ipdopts->parameters[i].paramType;
+ paramType = ipdopts->parameters[pidx].paramType;
oid = SOCK_get_int(sock, 4);
if (SQL_PARAM_OUTPUT != paramType ||
PG_TYPE_VOID != oid)
- ipdopts->parameters[i + stmt->proc_return].PGType = oid;
+ ipdopts->parameters[pidx].PGType = oid;
+ }
+ }
+#endif /* NOT_USED */
+ pidx = stmt->current_exec_param;
+ if (pidx >= 0)
+ pidx--;
+ for (i = 0; i < num_p; i++)
+ {
+ SC_param_next(stmt, &pidx, NULL, NULL);
+ if (pidx >= stmt->num_params)
+ {
+ mylog("%dth parameter's position(%d) is out of bound[%d]\n", i, pidx, stmt->num_params);
+ break;
}
+ oid = SOCK_get_int(sock, 4);
+ paramType = ipdopts->parameters[pidx].paramType;
+ if (SQL_PARAM_OUTPUT != paramType ||
+ PG_TYPE_VOID != oid)
+ ipdopts->parameters[pidx].PGType = oid;
}
break;
case 'T': /* RowDesription */
}
BOOL
-SendParseRequest(StatementClass *stmt, const char *plan_name, const char *query)
+SendParseRequest(StatementClass *stmt, const char *plan_name, const char *query, Int4 qlen, Int2 num_params)
{
CSTR func = "SendParseRequest";
ConnectionClass *conn = SC_get_conn(stmt);
SocketClass *sock = conn->sock;
+ Int4 sta_pidx, end_pidx;
size_t pileng, leng;
mylog("%s: plan_name=%s query=%s\n", func, plan_name, query);
+ qlog("%s: plan_name=%s query=%s\n", func, plan_name, query);
if (!RequestStart(stmt, conn, func))
return FALSE;
}
pileng = sizeof(Int2);
- if (!stmt->discard_output_params)
- pileng += sizeof(UInt4) * (stmt->num_params - stmt->proc_return);
- leng = strlen(plan_name) + 1 + strlen(query) + 1 + pileng;
+ if (stmt->discard_output_params)
+ num_params = 0;
+ else if (num_params != 0)
+ {
+#ifdef NOT_USED
+ sta_pidx += stmt->proc_return;
+#endif /* NOT_USED */
+ int pidx;
+
+ sta_pidx = stmt->current_exec_param;
+ if (num_params < 0)
+ end_pidx = stmt->num_params - 1;
+ else
+ end_pidx = sta_pidx + num_params - 1;
+#ifdef NOT_USED
+ num_params = end_pidx - sta_pidx + 1;
+#endif /* NOT_USED */
+ for (num_params = 0, pidx = sta_pidx - 1;;)
+ {
+ SC_param_next(stmt, &pidx, NULL, NULL);
+ if (pidx > end_pidx)
+ break;
+ else if (pidx < end_pidx)
+ num_params++;
+ else
+ {
+ num_params++;
+ break;
+ }
+ }
+mylog("sta_pidx=%d end_pidx=%d num_p=%d\n", sta_pidx, end_pidx, num_params);
+ pileng += (sizeof(UInt4) * 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);
SOCK_put_string(sock, plan_name);
- SOCK_put_string(sock, query);
- SOCK_put_int(sock, stmt->num_params - stmt->proc_return, sizeof(Int2)); /* number of parameters unspecified */
- if (!stmt->discard_output_params)
+ SOCK_put_n_char(sock, query, qlen);
+ SOCK_put_char(sock, '\0');
+ SOCK_put_int(sock, num_params, sizeof(Int2)); /* number of parameters specified */
+ if (num_params > 0)
{
int i;
IPDFields *ipdopts = SC_get_IPDF(stmt);
- for (i = stmt->proc_return; i < stmt->num_params; i++)
+ for (i = sta_pidx; i <= end_pidx; i++)
{
if (i < ipdopts->allocated &&
SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
if (sock = conn->sock, !sock) return FALSE;
mylog("%s: plan_name=%s count=%d\n", func, plan_name, count);
+ qlog("%s: plan_name=%s count=%d\n", func, plan_name, count);
if (!SC_is_fetchcursor(stmt))
{
switch (stmt->prepared)
}
leng = strlen(plan_name) + 1 + 4;
- SOCK_put_int(sock, (Int4) (leng + 4), 4); /* length */
+ SOCK_put_int(sock, (Int4) (leng + 4), sizeof(Int4)); /* length */
inolog("execute leng=%d\n", leng);
- SOCK_put_string(sock, plan_name);
- SOCK_put_int(sock, count, 4);
+ SOCK_put_string(sock, plan_name); /* portal name == plan name */
+ SOCK_put_int(sock, count, sizeof(Int4));
if (0 == count) /* will send a Close portal command */
{
SOCK_put_char(sock, 'C'); /* Close command */
TABLE_INFO **ti;
Int2 ntab;
Int2 num_key_fields;
- char parse_status;
- char proc_return;
Int2 statement_type; /* According to the defines above */
- int current_exec_param; /* The current parameter for
- * SQLPutData */
+ Int2 num_params;
+ Int2 data_at_exec; /* Number of params needing SQLPutData */
+ Int2 current_exec_param; /* The current parameter for
+ * SQLPutData */
PutDataInfo pdata_info;
+ char parse_status;
+ char proc_return;
char put_data; /* Has SQLPutData been called ? */
char catalog_result; /* Is this a result of catalog function ? */
char prepare; /* is this a prepared statement ? */
char ref_CC_error; /* refer to CC_error ? */
char lock_CC_for_rb; /* lock CC for statement rollback ? */
char join_info; /* have joins ? */
+ char parse_method; /* parse_statement is forced or ? */
pgNAME cursor_name;
char *plan_name;
- Int2 num_params;
- Int2 data_at_exec; /* Number of params needing SQLPutData */
char *stmt_with_params; /* statement after parameter
* substitution */
#define SC_checked_hasoids(a) (0 != (a->parse_status & STMT_PARSED_OIDS))
#define SC_set_delegate(p, c) (p->execute_delegate = c, c->execute_parent = p)
+#define SC_clear_parse_method(s) ((s)->parse_method = 0)
+#define SC_is_parse_forced(s) (0 != ((s)->parse_method & 1L))
+#define SC_set_parse_forced(s) ((s)->parse_method |= 1L)
+#define SC_is_parse_tricky(s) (0 != ((s)->parse_method & 2L))
+#define SC_set_parse_tricky(s) ((s)->parse_method |= 2L)
+#define SC_no_parse_tricky(s) ((s)->parse_method &= ~2L)
+
#define SC_cursor_is_valid(s) (NAME_IS_VALID(s->cursor_name))
#define SC_cursor_name(s) (SAFE_NAME(s->cursor_name))
char SC_Destructor(StatementClass *self);
BOOL SC_opencheck(StatementClass *self, const char *func);
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);
Int4 SC_pre_execute(StatementClass *self);
RETCODE SC_pos_add(StatementClass *self, SQLSETPOSIROW irow);
int SC_set_current_col(StatementClass *self, int col);
void SC_setInsertedTable(StatementClass *, RETCODE);
+void SC_scanQueryAndCountParams(const char *, const ConnectionClass *,
+ Int4 *next_cmd, SQLSMALLINT *num_params,
+ char *multi, char *proc_return);
BOOL SC_IsExecuting(const StatementClass *self);
BOOL SC_SetExecuting(StatementClass *self, BOOL on);
RETCODE DiscardStatementSvp(StatementClass *self, RETCODE, BOOL errorOnly);
BOOL SendParseRequest(StatementClass *self, const char *name,
- const char *query);
+ const char *query, Int4 qlen, Int2 num_params);
BOOL SendDescribeRequest(StatementClass *self, const char *name);
BOOL SendBindRequest(StatementClass *self, const char *name);
BOOL BuildBindRequest(StatementClass *stmt, const char *name);
#ifndef __VERSION_H__
#define __VERSION_H__
-#define POSTGRESDRIVERVERSION "08.02.0203"
-#define POSTGRES_RESOURCE_VERSION "08.02.0203\0"
-#define PG_DRVFILE_VERSION 8,2,02,03
+#define POSTGRESDRIVERVERSION "08.02.0204"
+#define POSTGRES_RESOURCE_VERSION "08.02.0204\0"
+#define PG_DRVFILE_VERSION 8,2,02,04
+#define PG_BUILD_VERSION "200703020002"
#endif
!MESSAGE Using default OpenSSL Library directory: $(SSL_LIB)
!ENDIF
+!IF "$(LINKMT)" == ""
+LINKMT=MT
+!ENDIF
+!IF "$(LINKMT)" == "MT"
+!MESSAGE Linking static Multithread library
+!ELSE
+!MESSAGE Linking dynamic Multithread library
+!ENDIF
+
SSL_DLL = "SSLEAY32.dll"
ADD_DEFINES = $(ADD_DEFINES) /D "SSL_DLL=\"$(SSL_DLL)\""
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+$(INTDIR)\connection.obj $(INTDIR)\psqlodbc.res: version.h
+
CPP=cl.exe
!IF "$(CFG)" == "Release"
-CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+CPP_PROJ=/nologo /$(LINKMT) /W3 /GX /O2 /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
!ELSEIF "$(CFG)" == "Debug"
-CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+CPP_PROJ=/nologo /$(LINKMT)d /W3 /Gm /GX /ZI /Od /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "PSQLODBC_EXPORTS" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
!ENDIF
.c{$(INTDIR)}.obj::