of ODBC escape { .
case NAMED_PARSE_REQUEST:
case PARSE_TO_EXEC_ONCE:
case PARSE_REQ_FOR_INFO:
- if (ret = prepareParameters(stmt), SQL_ERROR == ret)
+ if (ret = prepareParameters(stmt, TRUE), SQL_ERROR == ret)
goto cleanup;
}
}
void PDATA_free_params(PutDataInfo *pdata, char option);
void SC_param_next(const StatementClass*, int *param_number, ParameterInfoClass **, ParameterImplClass **);
-RETCODE prepareParameters(StatementClass *stmt);
+RETCODE prepareParameters(StatementClass *stmt, BOOL sync);
int decideHowToPrepare(StatementClass *stmt, BOOL force);
#endif
{
rv->status = CONN_NOT_CONNECTED;
rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */
+ rv->stmt_in_extquery = NULL;
CC_conninfo_init(&(rv->connInfo));
rv->sock = SOCK_Constructor(rv);
self->status = CONN_NOT_CONNECTED;
self->transact_status = CONN_IN_AUTOCOMMIT;
+ self->stmt_in_extquery = NULL;
CC_conninfo_init(&(self->connInfo));
if (self->original_client_encoding)
{
CC_set_in_error_trans(conn);
break;
}
+ conn->stmt_in_extquery = NULL;
}
return id;
}
return NULL;
}
+ /* Finish the pending extended query first */
+ if (!SyncParseRequest(self))
+ {
+ if (CC_get_errornumber(self) <= 0)
+ {
+ CC_set_error(self, CONN_EXEC_ERROR, "error occured while calling SyncParseRequest() in CC_send_query_append()", func);
+ return NULL;
+ }
+ }
/* Indicate that we are sending a query to the backend */
maxlen = CC_get_max_query_len(self);
qrylen = strlen(query);
return FALSE;
}
+ /* Finish the pending extended query first */
+ if (!SyncParseRequest(self))
+ {
+ if (CC_get_errornumber(self) <= 0)
+ {
+ CC_set_error(self, CONN_EXEC_ERROR, "error occured while calling SyncParseRequest() in CC_send_function()", func);
+ return FALSE;
+ }
+ }
#define return DONT_CALL_RETURN_FROM_HERE???
ENTER_INNER_CONN_CS(self, func_cs_count);
ci = &(self->connInfo);
int be_key; /* auth code needed to send cancel */
UInt4 isolation;
char *current_schema;
+ StatementClass *stmt_in_extquery;
Int2 max_identifier_length;
Int2 num_discardp;
char **discardp;
char token_save[64];
int token_len;
BOOL prev_token_end;
- BOOL proc_no_param;
size_t declare_pos;
UInt4 flags;
encoded_str encstr;
q->token_save[0] = '\0';
q->token_len = 0;
q->prev_token_end = TRUE;
- q->proc_no_param = TRUE;
q->declare_pos = 0;
q->flags = 0;
make_encoded_str(&q->encstr, SC_get_conn(stmt), q->statement);
Int2 num_output_params;
Int2 num_discard_params;
Int2 proc_return;
+ Int2 brace_level;
+ char parenthesize_the_first;
APDFields *apdopts;
IPDFields *ipdopts;
PutDataInfo *pdata;
qb->num_io_params = 0;
qb->num_output_params = 0;
qb->num_discard_params = 0;
+ qb->brace_level = 0;
+ qb->parenthesize_the_first = FALSE;
if (conn)
qb->conn = conn;
else if (stmt)
} while (0)
#endif /* NOT_USED */
+static RETCODE
+QB_start_brace(QueryBuild *qb)
+{
+ BOOL replace_by_parenthesis = TRUE;
+
+ if (0 == qb->brace_level)
+ {
+ if (0 == F_NewPos(qb))
+ {
+ qb->parenthesize_the_first = FALSE;
+ replace_by_parenthesis = FALSE;
+ }
+ else
+ qb->parenthesize_the_first = TRUE;
+ }
+ if (replace_by_parenthesis)
+ CVT_APPEND_CHAR(qb, '(');
+ qb->brace_level++;
+ return SQL_SUCCESS;
+}
+
+static RETCODE
+QB_end_brace(QueryBuild *qb)
+{
+ BOOL replace_by_parenthesis = TRUE;
+
+ if (qb->brace_level <= 1 &&
+ !qb->parenthesize_the_first)
+ replace_by_parenthesis = FALSE;
+ if (replace_by_parenthesis)
+ CVT_APPEND_CHAR(qb, ')');
+ qb->brace_level--;
+ return SQL_SUCCESS;
+}
+
+static RETCODE QB_append_space_to_separate_identifiers(QueryBuild *qb, const QueryParse *qp)
+{
+ unsigned char tchar = F_OldChar(qp);
+ encoded_str encstr;
+ BOOL add_space = FALSE;
+
+ if (ODBC_ESCAPE_END != tchar)
+ return SQL_SUCCESS;
+ encoded_str_constr(&encstr, qb->ccsc, F_OldPtr(qp) + 1);
+ tchar = encoded_nextchar(&encstr);
+ if (ENCODE_STATUS(encstr) != 0)
+ add_space = TRUE;
+ else
+ {
+ if (isalnum(tchar))
+ add_space = TRUE;
+ else
+ {
+ switch (tchar)
+ {
+ case '_':
+ case '$':
+ add_space = TRUE;
+ }
+ }
+ }
+ if (add_space)
+ CVT_APPEND_CHAR(qb, ' ');
+
+ return SQL_SUCCESS;
+}
+
/*----------
* Check if the statement is
* SELECT ... INTO table FROM .....
}
static
-RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb);
+RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb, BOOL sync);
static int
Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
{
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
BOOL discardOutput, outpara;
+ BOOL sync = FALSE;
if (PROTOCOL_74(ci))
{
if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
return SQL_ERROR;
if (PROTOCOL_74(ci))
- return prep_params(stmt, qp, qb);
+ return prep_params(stmt, qp, qb, sync);
discardOutput = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
if (NOT_YET_PREPARED == stmt->prepared) /* not yet prepared */
{
#endif /* NOT_USED */
CVT_APPEND_STR(qb, "PREPARE \"");
CVT_APPEND_STR(qb, plan_name);
- CVT_APPEND_CHAR(qb, '"');
+ CVT_APPEND_CHAR(qb, IDENTIFIER_QUOTE);
marker_count = stmt->num_params - qb->num_discard_params;
if (!ipdopts || ipdopts->allocated < marker_count)
{
if (outpara)
CVT_APPEND_STR(qb, "void");
else
- CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType, FALSE));
+ CVT_APPEND_STR(qb, pgtype_to_name(stmt, PIC_dsp_pgtype(stmt, ipdopts->parameters[i]), FALSE));
oc++;
}
CVT_APPEND_CHAR(qb, ')');
#define my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
static
-RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
+RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb, BOOL sync)
{
CSTR func = "prep_params";
RETCODE retval;
ret = SendParseRequest(stmt, plan_name, qb->query_statement, SQL_NTS, -1);
if (!ret)
goto cleanup;
- if (!once_descr && (!SendDescribeRequest(stmt, plan_name)))
+ if (!once_descr && (!SendDescribeRequest(stmt, plan_name, TRUE)))
goto cleanup;
SC_set_planname(stmt, plan_name);
+ SC_set_prepared(stmt, plan_name[0] ? PREPARING_PERMANENTLY : PREPARING_TEMPORARILY);
+ if (!sync)
+ {
+ retval = SQL_SUCCESS;
+ goto cleanup;
+ }
if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
{
SC_set_error(stmt, STMT_NO_RESPONSE, "commnication error while preapreand_describe", func);
stmt->current_exec_param = num_pa;
ret = SendParseRequest(stmt, plan_name, srvquery, endp2 < 0 ? SQL_NTS : endp2, num_p1);
if (!ret) goto cleanup;
- if (!once_descr && !SendDescribeRequest(stmt, plan_name))
+ if (!once_descr && !SendDescribeRequest(stmt, plan_name, TRUE))
goto cleanup;
if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
{
return retval;
}
-RETCODE prepareParameters(StatementClass *stmt)
+RETCODE prepareParameters(StatementClass *stmt, BOOL sync)
{
switch (stmt->prepared)
{
qb = &query_crt;
if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
return SQL_ERROR;
- return prep_params(stmt, qp, qb);
+ return prep_params(stmt, qp, qb, sync);
}
return SQL_SUCCESS;
}
char *new_statement;
- BOOL begin_first = FALSE, prepare_dummy_cursor = FALSE;
+ BOOL begin_first = FALSE, prepare_dummy_cursor = FALSE, bPrepConv;
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
SQLLEN current_row;
SC_set_pre_executable(stmt);
qb = &query_crt;
qb->query_statement = NULL;
- if (PREPARED_PERMANENTLY == stmt->prepared || (buildPrepareStatement && stmt->options.scroll_concurrency == SQL_CONCUR_READ_ONLY))
+ bPrepConv = FALSE;
+ if (PREPARED_PERMANENTLY == stmt->prepared)
+ bPrepConv = TRUE;
+ else if (buildPrepareStatement &&
+ SQL_CONCUR_READ_ONLY == stmt->options.scroll_concurrency)
+ bPrepConv = TRUE;
+ if (bPrepConv)
{
retval = Prepare_and_convert(stmt, qp, qb);
return retval;
}
+ SC_forget_unnamed(stmt);
+ buildPrepareStatement = FALSE;
if (ci->disallow_premature)
prepare_dummy_cursor = stmt->pre_executing;
{
Int4 taglen = 0;
encoded_str encstr;
- char tchar;
+ unsigned char tchar;
const char *sptr;
encoded_str_constr(&encstr, ccsc, tag + 1);
return taglen;
}
+static
+Int4 findIdentifier(const char *str, int ccsc, const char **nextdel)
+{
+ Int4 strlen = 0;
+ encoded_str encstr;
+ unsigned char tchar;
+ const char *sptr;
+ BOOL dquote = FALSE;
+
+ *nextdel = NULL;
+ encoded_str_constr(&encstr, ccsc, str);
+ for (sptr = str; *sptr; sptr++)
+ {
+ tchar = encoded_nextchar(&encstr);
+ if (ENCODE_STATUS(encstr) != 0)
+ continue;
+ if (sptr == str) /* the first character */
+ {
+ if (dquote = (IDENTIFIER_QUOTE == tchar))
+ continue;
+ if (!isalpha(tchar))
+ {
+ strlen = 0;
+ if (!isspace(tchar))
+ *nextdel = sptr;
+ break;
+ }
+ }
+ if (dquote)
+ {
+ if (IDENTIFIER_QUOTE == tchar)
+ {
+ if (IDENTIFIER_QUOTE == sptr[1])
+ {
+ encoded_nextchar(&encstr);
+ sptr++;
+ continue;
+ }
+ strlen = sptr - str + 1;
+ sptr++;
+ break;
+ }
+ }
+ else
+ {
+ if (isalnum(tchar))
+ continue;
+ if (isspace(tchar))
+ {
+ strlen = sptr - str;
+ break;
+ }
+ switch (tchar)
+ {
+ case '_':
+ case '$':
+ continue;
+ }
+ strlen = sptr - str;
+ *nextdel = sptr;
+ break;
+ }
+ }
+ if (NULL == *nextdel)
+ {
+ for (; *sptr; sptr++)
+ {
+ if (!isspace(*sptr))
+ {
+ *nextdel = sptr;
+ break;
+ }
+ }
+ }
+ return strlen;
+}
+
static int
inner_process_tokens(QueryParse *qp, QueryBuild *qb)
{
* Handle literals (date, time, timestamp) and ODBC scalar
* functions
*/
- else if (oldchar == '{')
+ else if (oldchar == ODBC_ESCAPE_START)
{
+ int npos = F_NewPos(qb);
+ BOOL addsp = TRUE;
+ unsigned char tchar;
+
if (SQL_ERROR == convert_escape(qp, qb))
{
if (0 == qb->errornumber)
mylog("%s convert_escape error\n", func);
return SQL_ERROR;
}
- if (isalnum((UCHAR)F_OldPtr(qp)[1]))
- CVT_APPEND_CHAR(qb, ' ');
return SQL_SUCCESS;
}
/* End of an escape sequence */
- else if (oldchar == '}')
+ else if (oldchar == ODBC_ESCAPE_END)
{
- if (qp->statement_type == STMT_TYPE_PROCCALL)
- {
- if (qp->proc_no_param)
- CVT_APPEND_STR(qb, "()");
- }
- else if (!isspace(F_OldPtr(qp)[1]))
- CVT_APPEND_CHAR(qb, ' ');
- return SQL_SUCCESS;
+ return QB_end_brace(qb);
}
else if (oldchar == '@' &&
strnicmp(F_OldPtr(qp), "@@identity", 10) == 0)
memset(bindreq + leng, 0, sizeof(Int2) * num_p); /* initialize by text format */
for (i = stmt->proc_return, j = 0; i < num_params; i++)
{
-inolog("%dth paramater type oid is %u\n", i, parameters[i].PGType);
+inolog("%dth parameter type oid is %u\n", i, PIC_dsp_pgtype(stmt, parameters[i]));
if (discard_output &&
SQL_PARAM_OUTPUT == parameters[i].paramType)
continue;
- if (PG_TYPE_BYTEA == parameters[i].PGType)
+ if (PG_TYPE_BYTEA == PIC_dsp_pgtype(stmt, parameters[i]))
{
mylog("%dth parameter is of binary format\n", j);
memcpy(bindreq + leng + sizeof(Int2) * j,
param_ctype = apara->CType;
param_sqltype = ipara->SQLType;
- param_pgtype = ipara->PGType;
+ param_pgtype = PIC_dsp_pgtype(qb->stmt, *ipara);
- mylog("%s: from(fcType)=%d, to(fSqlType)=%d\n", func,
- param_ctype, param_sqltype);
+ mylog("%s: from(fcType)=%d, to(fSqlType)=%d(%u)\n", func,
+ param_ctype, param_sqltype, param_pgtype);
/* replace DEFAULT with something we can use */
if (param_ctype == SQL_C_DEFAULT)
lobj_oid = pdata->pdata[param_number].lobj_oid;
else
{
+ BOOL is_in_trans_at_entry = CC_is_in_trans(conn);
+
/* begin transaction if needed */
- if (!CC_is_in_trans(conn))
+ if (!is_in_trans_at_entry)
{
if (!CC_begin(conn))
{
odbc_lo_close(conn, lobj_fd);
/* commit transaction if needed */
- if (!ci->drivers.use_declarefetch && CC_does_autocommit(conn))
+ if (!is_in_trans_at_entry)
{
if (!CC_commit(conn))
{
*output_count = F_NewPos(qb);
break;
- case '}':
+ case ODBC_ESCAPE_END:
stop = (0 == innerParenthesis);
break;
convert_escape(QueryParse *qp, QueryBuild *qb)
{
CSTR func = "convert_escape";
+ ConnectionClass *conn = qb->conn;
RETCODE retval = SQL_SUCCESS;
char buf[1024], buf_small[128], key[65];
UCHAR ucv;
UInt4 prtlen;
- if (F_OldChar(qp) == '{') /* skip the first { */
+ if (F_OldChar(qp) == ODBC_ESCAPE_START) /* skip the first { */
F_OldNext(qp);
/* Separate off the key, skipping leading and trailing whitespace */
while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv))
/*
* procedure calls
*/
+ /* '?=' to accept return values exists ? */
+ if (F_OldChar(qp) == '?')
+ {
+ qb->param_number++;
+ qb->proc_return = 1;
+ if (qb->stmt)
+ qb->stmt->proc_return = 1;
+ while (isspace((UCHAR) qp->statement[++qp->opos]));
+ if (F_OldChar(qp) != '=')
+ {
+ F_OldPrior(qp);
+ return SQL_SUCCESS;
+ }
+ while (isspace((UCHAR) qp->statement[++qp->opos]));
+ }
+ /**
+ if (qp->statement_type == STMT_TYPE_PROCCALL)
+ {
+ int lit_call_len = 4;
+
+ // '?=' to accept return values exists ?
+ if (F_OldChar(qp) == '?')
+ {
+ qb->param_number++;
+ qb->proc_return = 1;
+ if (qb->stmt)
+ qb->stmt->proc_return = 1;
+ while (isspace((UCHAR) qp->statement[++qp->opos]));
+ if (F_OldChar(qp) != '=')
+ {
+ F_OldPrior(qp);
+ return SQL_SUCCESS;
+ }
+ while (isspace((UCHAR) qp->statement[++qp->opos]));
+ }
+ if (strnicmp(F_OldPtr(qp), "call", lit_call_len) ||
+ !isspace((UCHAR) F_OldPtr(qp)[lit_call_len]))
+ {
+ F_OldPrior(qp);
+ return SQL_SUCCESS;
+ }
+ qp->opos += lit_call_len;
+ if (qb->num_io_params > 1 ||
+ (0 == qb->proc_return &&
+ PG_VERSION_GE(conn, 7.3)))
+ CVT_APPEND_STR(qb, "SELECT * FROM");
+ else
+ CVT_APPEND_STR(qb, "SELECT");
+ if (my_strchr(conn, F_OldPtr(qp), '('))
+ qp->proc_no_param = FALSE;
+ return SQL_SUCCESS;
+ }
+ **/
sscanf(F_OldPtr(qp), "%32s", key);
while ((ucv = F_OldChar(qp)) != '\0' && (!isspace(ucv)))
/* Avoid the concatenation of the function name with the previous word. Aceto */
- if (F_NewPos(qb) > 0 && isalnum((UCHAR)F_NewPtr(qb)[-1]))
- CVT_APPEND_CHAR(qb, ' ');
if (stricmp(key, "call") == 0)
{
Int4 funclen;
const char *nextdel;
+ if (SQL_ERROR == QB_start_brace(qb))
+ return SQL_ERROR;
if (qb->num_io_params > 1 ||
(0 == qb->proc_return &&
PG_VERSION_GE(conn, 7.3)))
CVT_APPEND_STR(qb, "SELECT * FROM ");
else
CVT_APPEND_STR(qb, "SELECT ");
- /* Continue at inner_process_tokens loop */
- F_OldPrior(qp);
- return SQL_SUCCESS;
+ funclen = findIdentifier(F_OldPtr(qp), qb->ccsc, &nextdel);
+ if (nextdel && ODBC_ESCAPE_END == *nextdel)
+ {
+ CVT_APPEND_DATA(qb, F_OldPtr(qp), funclen);
+ CVT_APPEND_STR(qb, "()");
+ if (SQL_ERROR == QB_end_brace(qb))
+ return SQL_ERROR;
+ /* positioned at } */
+ qp->opos += (nextdel - F_OldPtr(qp));
+ }
+ else
+ {
+ /* Continue at inner_process_tokens loop */
+ F_OldPrior(qp);
+ return SQL_SUCCESS;
+ }
}
else if (stricmp(key, "d") == 0)
{
/* Literal; return the escape part adding type cast */
- F_ExtractOldTo(qp, buf_small, '}', sizeof(buf_small));
- if (PG_VERSION_LT(qb->conn, 7.3))
- prtlen = snprintf(buf, sizeof(buf), "%s ", buf_small);
+ F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
+ if (PG_VERSION_LT(conn, 7.3))
+ prtlen = snprintf(buf, sizeof(buf), "%s", buf_small);
else
- prtlen = snprintf(buf, sizeof(buf), "%s::date ", buf_small);
+ prtlen = snprintf(buf, sizeof(buf), "%s::date", buf_small);
CVT_APPEND_DATA(qb, buf, prtlen);
+ retval = QB_append_space_to_separate_identifiers(qb, qp);
}
else if (stricmp(key, "t") == 0)
{
/* Literal; return the escape part adding type cast */
- F_ExtractOldTo(qp, buf_small, '}', sizeof(buf_small));
+ F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
prtlen = snprintf(buf, sizeof(buf), "%s::time", buf_small);
CVT_APPEND_DATA(qb, buf, prtlen);
+ retval = QB_append_space_to_separate_identifiers(qb, qp);
}
else if (stricmp(key, "ts") == 0)
{
/* Literal; return the escape part adding type cast */
- F_ExtractOldTo(qp, buf_small, '}', sizeof(buf_small));
- if (PG_VERSION_LT(qb->conn, 7.1))
+ F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
+ if (PG_VERSION_LT(conn, 7.1))
prtlen = snprintf(buf, sizeof(buf), "%s::datetime", buf_small);
else
prtlen = snprintf(buf, sizeof(buf), "%s::timestamp", buf_small);
CVT_APPEND_DATA(qb, buf, prtlen);
+ retval = QB_append_space_to_separate_identifiers(qb, qp);
}
else if (stricmp(key, "oj") == 0) /* {oj syntax support for 7.1 * servers */
{
if (qb->stmt)
SC_set_outer_join(qb->stmt);
+ retval = QB_start_brace(qb);
+ /* Continue at inner_process_tokens loop */
F_OldPrior(qp);
- return SQL_SUCCESS; /* Continue at inner_process_tokens loop */
+ return retval;
}
- else if (stricmp(key, "escape") == 0) /* like escape support for 7.1+ servers */
+ else if (stricmp(key, "escape") == 0) /* like escape syntax support for 7.1+ servers */
{
- CVT_APPEND_STR(qb, key);
- return SQL_SUCCESS;
+ /* Literal; return the escape part adding type cast */
+ F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
+ prtlen = snprintf(buf, sizeof(buf), "%s %s", key, buf_small);
+ CVT_APPEND_DATA(qb, buf, prtlen);
+ retval = QB_append_space_to_separate_identifiers(qb, qp);
}
else if (stricmp(key, "fn") == 0)
{
st->infinity = 0;
/* escape sequence ? */
- if (buf[0] == '{')
+ if (buf[0] == ODBC_ESCAPE_START)
{
while (*(++buf) && *buf != LITERAL_QUOTE);
if (!(*buf))
GetDataInfo *gdata_info = SC_get_GDTI(stmt);
int factor;
+ oid = ATOI32U(value);
+ if (0 == oid)
+ {
+ if (pcbValue)
+ *pcbValue = SQL_NULL_DATA;
+ return COPY_OK;
+ }
switch (fCType)
{
case SQL_C_CHAR:
}
}
- oid = ATOI32U(value);
stmt->lobj_fd = odbc_lo_open(conn, oid, INV_READ);
if (stmt->lobj_fd < 0)
{
return method;
}
+/* dont/should/can send Parse request ? */
+enum {
+ doNothing = 0
+ ,allowParse
+ ,preferParse
+ ,shouldParse
+ ,usingCommand
+};
+
+#define ONESHOT_CALL_PARSE allowParse
+#define NOPARAM_ONESHOT_CALL_PARSE doNothing
+
+static
+int HowToPrepareBeforeExec(StatementClass *stmt, BOOL checkOnly)
+{
+ SQLSMALLINT num_params = stmt->num_params;
+ ConnectionClass *conn = SC_get_conn(stmt);
+ ConnInfo *ci = &(conn->connInfo);
+ int nCallParse = doNothing, how_to_prepare = 0;
+ BOOL bNeedsTrans = FALSE;
+
+ if (num_params < 0)
+ PGAPI_NumParams(stmt, &num_params);
+ how_to_prepare = decideHowToPrepare(stmt, checkOnly);
+ if (checkOnly)
+ {
+ if (num_params <= 0)
+ return doNothing;
+ }
+ else
+ {
+ switch (how_to_prepare)
+ {
+ case USING_PREPARE_COMMAND:
+ return usingCommand;
+ case NAMED_PARSE_REQUEST:
+ return shouldParse;
+ case PARSE_TO_EXEC_ONCE:
+ switch (stmt->prepared)
+ {
+ case PREPARED_TEMPORARILY:
+ nCallParse = preferParse;
+ break;
+ default:
+ if (num_params <= 0)
+ nCallParse = NOPARAM_ONESHOT_CALL_PARSE;
+ else
+ nCallParse = ONESHOT_CALL_PARSE;
+ }
+ break;
+ default:
+ return doNothing;
+ }
+ }
+ if (PG_VERSION_LE(conn, 7.3))
+ return nCallParse;
+
+ if (num_params > 0)
+ {
+ int param_number = -1;
+ ParameterInfoClass *apara;
+ ParameterImplClass *ipara;
+ OID pgtype;
+
+ while (TRUE)
+ {
+ SC_param_next(stmt, ¶m_number, &apara, &ipara);
+ if (!ipara || !apara)
+ break;
+ pgtype = PIC_get_pgtype(*ipara);
+ if (checkOnly)
+ {
+ switch (ipara->SQLType)
+ {
+ case SQL_LONGVARBINARY:
+ if (0 == pgtype)
+ {
+ if (ci->bytea_as_longvarbinary &&
+ 0 != conn->lobj_type)
+ nCallParse = shouldParse;
+ }
+ break;
+ case SQL_CHAR:
+ if (ci->cvt_null_date_string)
+ nCallParse = shouldParse;
+ break;
+ }
+ }
+ else
+ {
+ BOOL bBytea = FALSE;
+
+ switch (ipara->SQLType)
+ {
+ case SQL_LONGVARBINARY:
+ if (conn->lobj_type == pgtype ||
+ PG_TYPE_OID == pgtype)
+ bNeedsTrans = TRUE;
+ else if (PG_TYPE_BYTEA == pgtype)
+ bBytea = TRUE;
+ else if (0 == pgtype)
+ {
+ if (ci->bytea_as_longvarbinary)
+ bBytea = TRUE;
+ else
+ bNeedsTrans = TRUE;
+ }
+ if (bBytea)
+ if (nCallParse < preferParse)
+ nCallParse = preferParse;
+ break;
+ }
+ }
+ }
+ }
+ if (bNeedsTrans &&
+ PARSE_TO_EXEC_ONCE == how_to_prepare)
+ {
+ if (!CC_is_in_trans(conn) && CC_does_autocommit(conn))
+ nCallParse = doNothing;
+ }
+ return nCallParse;
+}
+
/*
* The execution after all parameters were resolved.
*/
/* Prepare the statement if possible at backend side */
if (!stmt->inaccurate_result)
{
+ /**
switch (decideHowToPrepare(stmt, FALSE))
{
case USING_PREPARE_COMMAND:
case NAMED_PARSE_REQUEST:
#ifndef BYPASS_ONESHOT_PLAN_EXECUTION
case PARSE_TO_EXEC_ONCE:
-#endif/* BYPASS_ONESHOT_PLAN_EXECUTION */
+#endif
prepare_before_exec = TRUE;
}
+ **/
+ if (HowToPrepareBeforeExec(stmt, FALSE) >= allowParse)
+ prepare_before_exec = TRUE;
}
inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.use_server_side_prepare);
/* Create the statement with parameters substituted. */
We sometimes need to know about the PG type of binding
parameters even in case of non-prepared statements.
*/
- BOOL bCallPrepare = FALSE;
-
- ConnInfo *ci = &(conn->connInfo);
- if (NOT_YET_PREPARED == stmt->prepared &&
- PROTOCOL_74(ci) &&
- ci->use_server_side_prepare &&
- (ci->bytea_as_longvarbinary || /* both lo and bytea are LO */
- ci->cvt_null_date_string))
+ int nCallParse = doNothing;
+
+ if (NOT_YET_PREPARED == stmt->prepared)
{
- SQLSMALLINT num_params = stmt->num_params;
- if (num_params < 0)
- PGAPI_NumParams(stmt, &num_params);
- if (num_params > 0)
+ switch (nCallParse = HowToPrepareBeforeExec(stmt, TRUE))
{
- int param_number = -1;
- ParameterInfoClass *apara;
- ParameterImplClass *ipara;
- BOOL reqOK = FALSE;
-
- switch (decideHowToPrepare(stmt, TRUE))
- {
- case NAMED_PARSE_REQUEST:
- case PARSE_TO_EXEC_ONCE:
- case PARSE_REQ_FOR_INFO:
- reqOK = TRUE;
- }
- while (reqOK)
- {
- SC_param_next(stmt, ¶m_number, &apara, &ipara);
- if (!ipara || !apara)
- break;
- if (SQL_LONGVARBINARY == ipara->SQLType)
- {
- if (ci->bytea_as_longvarbinary)
- {
- bCallPrepare = TRUE;
- break;
- }
- }
- else if (SQL_CHAR == ipara->SQLType)
- {
- if (SQL_C_CHAR == apara->CType &&
- ci->cvt_null_date_string)
- {
- bCallPrepare = TRUE;
- break;
- }
- }
- }
+ case shouldParse:
+ if (retval = prepareParameters(stmt, TRUE), SQL_ERROR == retval)
+ goto cleanup;
+ break;
}
}
- if (bCallPrepare)
- {
- if (retval = prepareParameters(stmt), SQL_ERROR == retval)
- goto cleanup;
- }
-mylog("prepareParameters %d end\n", stmt->prepare);
+mylog("prepareParameters was %s called, prepare state:%d\n", shouldParse == nCallParse ? "" : "not", stmt->prepare);
if (ipdopts->param_processed_ptr)
*ipdopts->param_processed_ptr = 0;
char *buffer, *putbuf, *allocbuf = NULL;
Int2 ctype;
SQLLEN putlen;
- BOOL lenset = FALSE;
+ BOOL lenset = FALSE, handling_lo = FALSE;
mylog("%s: entering...\n", func);
putlen = ctype_length(ctype);
}
putbuf = rgbValue;
- if (current_iparam->PGType == conn->lobj_type && SQL_C_CHAR == ctype)
+ handling_lo = (PIC_dsp_pgtype(stmt, *current_iparam) == conn->lobj_type);
+ if (handling_lo && SQL_C_CHAR == ctype)
{
allocbuf = malloc(putlen / 2 + 1);
if (allocbuf)
/* Handle Long Var Binary with Large Objects */
/* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
- if (current_iparam->PGType == conn->lobj_type)
+ if (handling_lo)
{
/* begin transaction if needed */
if (!CC_is_in_trans(conn))
mylog("PGAPI_PutData: (>1) cbValue = %d\n", cbValue);
/* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
- if (current_iparam->PGType == conn->lobj_type)
+ if (handling_lo)
{
/* the large object fd is in EXEC_buffer */
retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, (Int4) putlen);
SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
const char *szSchemaName, *eq_string;
- mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType);
+ mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d scope=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType, fScope);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
static char
parse_the_statement(StatementClass *stmt, BOOL check_hasoids, BOOL sqlsvr_check)
{
- CSTR func = "parse_statement";
+ CSTR func = "parse_the_statement";
char token[TOKEN_SIZE], stoken[TOKEN_SIZE], btoken[TOKEN_SIZE];
char delim,
quote,
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: psqlodbc.h,v 1.131 2009/07/06 15:23:02 h-saito Exp $
+ * $Id: psqlodbc.h,v 1.132 2009/10/25 13:36:31 hinoue Exp $
*
*/
#define SEARCH_PATTERN_ESCAPE '\\'
#define LITERAL_QUOTE '\''
#define IDENTIFIER_QUOTE '\"'
+#define ODBC_ESCAPE_START '{'
+#define ODBC_ESCAPE_END '}'
#define DOLLAR_QUOTE '$'
#define LITERAL_EXT 'E'
#define PG_CARRIAGE_RETURN '\r'
{
case NAMED_PARSE_REQUEST:
case PARSE_TO_EXEC_ONCE:
- if (SQL_SUCCESS != prepareParameters(self))
+ if (SQL_SUCCESS != prepareParameters(self, TRUE))
return num_fields;
break;
case PARSE_REQ_FOR_INFO:
- if (SQL_SUCCESS != prepareParameters(self))
+ if (SQL_SUCCESS != prepareParameters(self, TRUE))
return num_fields;
self->status = STMT_PREMATURE;
self->inaccurate_result = TRUE;
*/
/* in copy_statement... */
use_extended_protocol = FALSE;
- if (PREPARED_PERMANENTLY == self->prepared &&
- PROTOCOL_74(ci))
- use_extended_protocol = TRUE;
- else if (PREPARED_TEMPORARILY == self->prepared)
+ switch (self->prepared)
{
- switch (SC_get_prepare_method(self))
- {
+ case PREPARING_PERMANENTLY:
+ case PREPARED_PERMANENTLY:
+ if (PROTOCOL_74(ci))
+ use_extended_protocol = TRUE;
+ break;
+ case PREPARING_TEMPORARILY:
+ case PREPARED_TEMPORARILY:
+ if (!issue_begin)
+ {
+ switch (SC_get_prepare_method(self))
+ {
#ifndef BYPASS_ONESHOT_PLAN_EXECUTION
- case PARSE_TO_EXEC_ONCE:
+ case PARSE_TO_EXEC_ONCE:
#endif /* BYPASS_ONESHOT_PLAN_EXECUTION */
- case NAMED_PARSE_REQUEST:
- use_extended_protocol = TRUE;
- }
- if (!use_extended_protocol)
- {
- SC_forget_unnamed(self);
- SC_set_Result(self, NULL); /* discard the parsed information */
- }
+ case NAMED_PARSE_REQUEST:
+ use_extended_protocol = TRUE;
+ }
+ }
+ if (!use_extended_protocol)
+ {
+ SC_forget_unnamed(self);
+ SC_set_Result(self, NULL); /* discard the parsed information */
+ }
}
if (use_extended_protocol)
{
if (issue_begin)
CC_begin(conn);
- 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))
SC_set_error(self, STMT_EXEC_ERROR, "Execute request error", func);
goto cleanup;
}
+ for (res = SC_get_Result(self); NULL != res && NULL != res->next; res = res->next) ;
+inolog("get_Result=%p %p %d\n", res, SC_get_Result(self), self->curr_param_result);
if (!(res = SendSyncAndReceive(self, self->curr_param_result ? res : NULL, "bind_and_execute")))
{
if (SC_get_errornumber(self) <= 0)
return FALSE;
if (!BuildBindRequest(stmt, plan_name))
return FALSE;
+ conn->stmt_in_extquery = stmt;
return TRUE;
}
case 'E': /* ErrorMessage */
msg_truncated = handle_error_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
- rcvend = TRUE;
break;
case 'N': /* Notice */
msg_truncated = handle_notice_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
continue;
}
oid = SOCK_get_int(sock, 4);
- ipdopts->parameters[pidx].PGType = oid;
+ PIC_set_pgtype(ipdopts->parameters[pidx], oid);
}
}
else
oid = SOCK_get_int(sock, 4);
if (SQL_PARAM_OUTPUT != paramType ||
PG_TYPE_VOID != oid)
- ipdopts->parameters[pidx].PGType = oid;
+ PIC_set_pgtype(ipdopts->parameters[pidx], oid);
}
}
#endif /* NOT_USED */
paramType = ipdopts->parameters[pidx].paramType;
if (SQL_PARAM_OUTPUT != paramType ||
PG_TYPE_VOID != oid)
- ipdopts->parameters[pidx].PGType = oid;
+ PIC_set_pgtype(ipdopts->parameters[pidx], oid);
}
break;
case 'T': /* RowDesription */
if (SQL_PARAM_OUTPUT == paramType ||
SQL_PARAM_INPUT_OUTPUT == paramType)
{
-inolog("!![%d].PGType %u->%u\n", i, ipdopts->parameters[i].PGType, CI_get_oid(res->fields, cidx));
- ipdopts->parameters[i].PGType = CI_get_oid(res->fields, cidx);
+inolog("!![%d].PGType %u->%u\n", i, PIC_get_pgtype(ipdopts->parameters[i]), CI_get_oid(res->fields, cidx));
+ PIC_set_pgtype(ipdopts->parameters[i], CI_get_oid(res->fields, cidx));
cidx++;
}
}
break;
}
}
+ conn->stmt_in_extquery = NULL;
return res;
}
qlen = (SQL_NTS == qlen) ? strlen(query) : qlen;
leng = strlen(plan_name) + 1 + qlen + 1 + pileng;
SOCK_put_int(sock, (Int4) (leng + 4), 4); /* length */
-/* inolog("parse leng=%d\n", leng); */
inolog("parse leng=" FORMAT_SIZE_T "\n", leng);
SOCK_put_string(sock, plan_name);
SOCK_put_n_char(sock, query, qlen);
SOCK_put_int(sock, 0, sizeof(UInt4));
}
}
+ conn->stmt_in_extquery = stmt;
return TRUE;
}
+BOOL SyncParseRequest(ConnectionClass *conn)
+{
+ StatementClass *stmt = conn->stmt_in_extquery;
+ QResultClass *res, *last;
+ BOOL ret = FALSE;
+
+ if (!stmt)
+ return TRUE;
+
+ res = SC_get_Result(stmt);
+ for (last = res; last && last->next; last = last->next)
+ ;
+ if (!(res = SendSyncAndReceive(stmt, stmt->curr_param_result ? last : NULL, __FUNCTION__)))
+ {
+ if (SC_get_errornumber(stmt) <= 0)
+ SC_set_error(stmt, STMT_NO_RESPONSE, "Could not receive the response, communication down ??", __FUNCTION__);
+ CC_on_abort(conn, CONN_DEAD);
+ goto cleanup;
+ }
+
+ if (!last)
+ SC_set_Result(stmt, res);
+ else
+ {
+ if (res != last)
+ last->next = res;
+ stmt->curr_param_result = 1;
+ }
+ if (!QR_command_maybe_successful(res))
+ {
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Error while syncing parse reuest", __FUNCTION__);
+ goto cleanup;
+ }
+ ret = TRUE;
+cleanup:
+ return ret;
+}
+
BOOL
-SendDescribeRequest(StatementClass *stmt, const char *plan_name)
+SendDescribeRequest(StatementClass *stmt, const char *plan_name, BOOL paramAlso)
{
CSTR func = "SendDescribeRequest";
ConnectionClass *conn = SC_get_conn(stmt);
if (!sockerr)
{
inolog("describe leng=%d\n", leng);
- SOCK_put_char(sock, 'S'); /* describe a prepared statement */
+ SOCK_put_char(sock, paramAlso ? 'S' : 'P'); /* describe a prepared statement */
if (SOCK_get_errcode(sock) != 0)
sockerr = TRUE;
}
CC_on_abort(conn, CONN_DEAD);
return FALSE;
}
+ conn->stmt_in_extquery = stmt;
return TRUE;
}
SOCK_put_char(sock, 'P'); /* Portal */
SOCK_put_string(sock, plan_name);
}
+ conn->stmt_in_extquery = stmt;
return TRUE;
}
SOCK_put_char(sock, 'S'); /* Sync command */
SOCK_put_int(sock, 4, 4);
SOCK_flush_output(sock);
+ conn->stmt_in_extquery = NULL;
return TRUE;
}
LEAVE_COMMON_CS;
return exeSet;
}
+
+#ifdef NOT_USED
BOOL SC_SetCancelRequest(StatementClass *self)
{
BOOL enteredCS = FALSE;
LEAVE_COMMON_CS;
return enteredCS;
}
+#endif /* NOT_USED */
+
BOOL SC_AcceptedCancelRequest(const StatementClass *self)
{
BOOL shouldCancel = FALSE;
enum
{
NOT_YET_PREPARED = 0
+ ,PREPARING_PERMANENTLY
+ ,PREPARING_TEMPORARILY
,PREPARED_PERMANENTLY
,PREPARED_TEMPORARILY
,ONCE_DESCRIBED
#define SC_ref_CC_error(a) ((a->ref_CC_error) = TRUE)
#define SC_forget_unnamed(a) (PREPARED_TEMPORARILY == (a)->prepared ? SC_set_prepared(a, ONCE_DESCRIBED) : (void) 0)
#define SC_returns_rows(a) (STMT_TYPE_SELECT == (a)->statement_type || STMT_TYPE_WITH == (a)->statement_type)
+#define SC_determine_statement_type(a) (STMT_TYPE_SELECT != (a)->statement_type ? (a)->statement_type : ((a)->statement_type = || statement_type((a)->statement)))
/* For Multi-thread */
BOOL SendParseRequest(StatementClass *self, const char *name,
const char *query, Int4 qlen, Int2 num_params);
-BOOL SendDescribeRequest(StatementClass *self, const char *name);
+BOOL SyncParseRequest(ConnectionClass *conn);
+BOOL SendDescribeRequest(StatementClass *self, const char *name, BOOL paramAlso);
BOOL SendBindRequest(StatementClass *self, const char *name);
BOOL BuildBindRequest(StatementClass *stmt, const char *name);
BOOL SendExecuteRequest(StatementClass *stmt, const char *portal, UInt4 count);
#define POSTGRESDRIVERVERSION "08.04.0101"
#define POSTGRES_RESOURCE_VERSION "08.04.0101\0"
#define PG_DRVFILE_VERSION 8,4,01,01
-#define PG_BUILD_VERSION "200910250003"
+#define PG_BUILD_VERSION "200910250004"
#endif