mirror of
https://github.com/postgres/postgres.git
synced 2025-05-25 00:04:05 -04:00
1) Support Keyset Driven driver cursors.
2) Supprt ARD precision/scale and SQL_C_NUEMRIC. 3) Minimal implementation of SQLGetDiagField(). 4) SQLRowCount() reports the result of SQLSetPos and SQLBulkOperation. 5) int8 -> SQL_NUMERIC for Microsoft Jet. 6) Support isolation level change. 7) ODBC3.0 SQLSTATE code. 8) Append mode log files.
This commit is contained in:
parent
6c6f395a8a
commit
79420840ee
@ -69,6 +69,23 @@ PGAPI_BindParameter(
|
||||
opts->parameters[ipar].SQLType = fSqlType;
|
||||
opts->parameters[ipar].column_size = cbColDef;
|
||||
opts->parameters[ipar].decimal_digits = ibScale;
|
||||
opts->parameters[ipar].precision = 0;
|
||||
opts->parameters[ipar].scale = 0;
|
||||
#if (ODBCVER >= 0x0300)
|
||||
switch (fCType)
|
||||
{
|
||||
case SQL_C_NUMERIC:
|
||||
if (cbColDef > 0)
|
||||
opts->parameters[ipar].precision = (UInt2) cbColDef;
|
||||
if (ibScale > 0)
|
||||
opts->parameters[ipar].scale = ibScale;
|
||||
break;
|
||||
case SQL_C_TYPE_TIMESTAMP:
|
||||
if (ibScale > 0)
|
||||
opts->parameters[ipar].precision = ibScale;
|
||||
break;
|
||||
}
|
||||
#endif /* ODBCVER */
|
||||
|
||||
/*
|
||||
* If rebinding a parameter that had data-at-exec stuff in it, then
|
||||
@ -210,6 +227,8 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
|
||||
free(opts->bindings[icol].ttlbuf);
|
||||
opts->bindings[icol].ttlbuf = NULL;
|
||||
opts->bindings[icol].ttlbuflen = 0;
|
||||
opts->bindings[icol].precision = 0;
|
||||
opts->bindings[icol].scale = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -218,6 +237,13 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
|
||||
opts->bindings[icol].buffer = rgbValue;
|
||||
opts->bindings[icol].used = pcbValue;
|
||||
opts->bindings[icol].returntype = fCType;
|
||||
#if (ODBCVER >= 0x0300)
|
||||
if (SQL_C_NUMERIC == fCType)
|
||||
opts->bindings[icol].precision = 32;
|
||||
else
|
||||
#endif /* ODBCVER */
|
||||
opts->bindings[icol].precision = 0;
|
||||
opts->bindings[icol].scale = 0;
|
||||
|
||||
mylog(" bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
|
||||
}
|
||||
@ -460,6 +486,8 @@ reset_a_parameter_binding(APDFields *self, int ipar)
|
||||
self->parameters[ipar].SQLType = 0;
|
||||
self->parameters[ipar].column_size = 0;
|
||||
self->parameters[ipar].decimal_digits = 0;
|
||||
self->parameters[ipar].precision = 0;
|
||||
self->parameters[ipar].scale = 0;
|
||||
self->parameters[ipar].data_at_exec = FALSE;
|
||||
self->parameters[ipar].lobj_oid = 0;
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ struct BindInfoClass_
|
||||
Int2 returntype; /* kind of conversion to be applied when
|
||||
* returning (SQL_C_DEFAULT,
|
||||
* SQL_C_CHAR...) */
|
||||
Int2 precision; /* the precision for numeric or timestamp type */
|
||||
Int2 scale; /* the scale for numeric type */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -40,12 +42,14 @@ struct ParameterInfoClass_
|
||||
Int2 paramType;
|
||||
Int2 CType;
|
||||
Int2 SQLType;
|
||||
UInt4 column_size;
|
||||
Int2 decimal_digits;
|
||||
UInt4 column_size;
|
||||
Oid lobj_oid;
|
||||
Int4 *EXEC_used; /* amount of data OR the oid of the large
|
||||
* object */
|
||||
char *EXEC_buffer; /* the data or the FD of the large object */
|
||||
Int2 precision; /* the precision for numeric or timestamp type */
|
||||
Int2 scale; /* the scale for numeric type */
|
||||
char data_at_exec;
|
||||
};
|
||||
|
||||
|
@ -237,7 +237,7 @@ CC_conninfo_init(ConnInfo *conninfo)
|
||||
{
|
||||
memset(conninfo, 0, sizeof(ConnInfo));
|
||||
conninfo->disallow_premature = -1;
|
||||
conninfo->updatable_cursors = -1;
|
||||
conninfo->allow_keyset = -1;
|
||||
conninfo->lf_conversion = -1;
|
||||
conninfo->true_is_minus1 = -1;
|
||||
memcpy(&(conninfo->drivers), &globals, sizeof(globals));
|
||||
@ -293,6 +293,7 @@ CC_Constructor()
|
||||
rv->unicode = 0;
|
||||
rv->result_uncommitted = 0;
|
||||
rv->schema_support = 0;
|
||||
rv->isolation = SQL_TXN_READ_COMMITTED;
|
||||
#ifdef MULTIBYTE
|
||||
rv->client_encoding = NULL;
|
||||
rv->server_encoding = NULL;
|
||||
@ -996,6 +997,12 @@ another_version_retry:
|
||||
}
|
||||
#endif /* UNICODE_SUPPORT */
|
||||
#endif /* MULTIBYTE */
|
||||
ci->updatable_cursors = 0;
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
if (!ci->drivers.use_declarefetch &&
|
||||
PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
|
||||
ci->updatable_cursors = ci->allow_keyset;
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
|
||||
CC_clear_error(self); /* clear any initial command errors */
|
||||
self->status = CONN_CONNECTED;
|
||||
@ -1130,7 +1137,7 @@ void CC_on_commit(ConnectionClass *conn)
|
||||
}
|
||||
conn->result_uncommitted = 0;
|
||||
}
|
||||
void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
|
||||
void CC_on_abort(ConnectionClass *conn, UDWORD opt)
|
||||
{
|
||||
if (CC_is_in_trans(conn))
|
||||
{
|
||||
@ -1138,9 +1145,11 @@ void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans)
|
||||
if (conn->result_uncommitted)
|
||||
ProcessRollback(conn, TRUE);
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
if (set_no_trans)
|
||||
if (0 != (opt & NO_TRANS))
|
||||
CC_set_no_trans(conn);
|
||||
}
|
||||
if (0 != (opt & CONN_DEAD))
|
||||
conn->status = CONN_DOWN;
|
||||
conn->result_uncommitted = 0;
|
||||
}
|
||||
|
||||
@ -1162,8 +1171,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
BOOL clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
|
||||
create_keyset = ((flag & CREATE_KEYSET) != 0),
|
||||
issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
|
||||
char swallow,
|
||||
*wq;
|
||||
char swallow, *wq, *ptr;
|
||||
int id;
|
||||
SocketClass *sock = self->sock;
|
||||
int maxlen,
|
||||
@ -1173,8 +1181,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
query_completed = FALSE,
|
||||
before_64 = PG_VERSION_LT(self, 6.4),
|
||||
aborted = FALSE,
|
||||
used_passed_result_object = FALSE,
|
||||
set_no_trans;
|
||||
used_passed_result_object = FALSE;
|
||||
UDWORD abort_opt;
|
||||
|
||||
/* ERROR_MSG_LENGTH is suffcient */
|
||||
static char msgbuffer[ERROR_MSG_LENGTH + 1];
|
||||
@ -1201,7 +1209,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
{
|
||||
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
||||
self->errormsg = "Could not send Query to backend";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1210,7 +1218,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
{
|
||||
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
||||
self->errormsg = "Could not send Query to backend";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1223,7 +1231,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
{
|
||||
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
||||
self->errormsg = "Could not send Query to backend";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1260,7 +1268,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
self->errormsg = "No response from the backend";
|
||||
|
||||
mylog("send_query: 'id' - %s\n", self->errormsg);
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
ReadyToReturn = TRUE;
|
||||
retres = NULL;
|
||||
break;
|
||||
@ -1284,7 +1292,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
self->errornumber = CONNECTION_NO_RESPONSE;
|
||||
self->errormsg = "No response from backend while receiving a portal query command";
|
||||
mylog("send_query: 'C' - %s\n", self->errormsg);
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
ReadyToReturn = TRUE;
|
||||
retres = NULL;
|
||||
}
|
||||
@ -1312,11 +1320,20 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
|
||||
CC_on_commit(self);
|
||||
else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS);
|
||||
else if (strnicmp(cmdbuffer, "END", 3) == 0)
|
||||
CC_on_commit(self);
|
||||
else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS);
|
||||
else
|
||||
{
|
||||
trim(cmdbuffer); /* get rid of trailing space */
|
||||
ptr = strrchr(cmdbuffer, ' ');
|
||||
if (ptr)
|
||||
res->recent_processed_row_count = atoi(ptr + 1);
|
||||
else
|
||||
res->recent_processed_row_count = -1;
|
||||
}
|
||||
|
||||
if (QR_command_successful(res))
|
||||
QR_set_status(res, PGRES_COMMAND_OK);
|
||||
@ -1400,15 +1417,15 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
qlog("ERROR from backend during send_query: '%s'\n", msgbuffer);
|
||||
|
||||
/* We should report that an error occured. Zoltan */
|
||||
set_no_trans = FALSE;
|
||||
abort_opt = 0;
|
||||
if (!strncmp(msgbuffer, "FATAL", 5))
|
||||
{
|
||||
self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
|
||||
set_no_trans = TRUE;
|
||||
abort_opt = NO_TRANS | CONN_DEAD;
|
||||
}
|
||||
else
|
||||
self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
|
||||
CC_on_abort(self, set_no_trans);
|
||||
CC_on_abort(self, abort_opt);
|
||||
QR_set_status(res, PGRES_FATAL_ERROR);
|
||||
QR_set_message(res, msgbuffer);
|
||||
QR_set_aborted(res, TRUE);
|
||||
@ -1497,7 +1514,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
|
||||
default:
|
||||
self->errornumber = CONNECTION_BACKEND_CRAZY;
|
||||
self->errormsg = "Unexpected protocol character from backend (send_query)";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
|
||||
mylog("send_query: error - %s\n", self->errormsg);
|
||||
ReadyToReturn = TRUE;
|
||||
@ -1585,7 +1602,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
|
||||
{
|
||||
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
||||
self->errormsg = "Could not send function to backend";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1594,7 +1611,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
|
||||
{
|
||||
self->errornumber = CONNECTION_COULD_NOT_SEND;
|
||||
self->errormsg = "Could not send function to backend";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1643,7 +1660,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
|
||||
case 'E':
|
||||
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||
self->errormsg = msgbuffer;
|
||||
CC_on_abort(self, FALSE);
|
||||
CC_on_abort(self, 0);
|
||||
|
||||
mylog("send_function(V): 'E' - %s\n", self->errormsg);
|
||||
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
|
||||
@ -1656,7 +1673,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
|
||||
default:
|
||||
self->errornumber = CONNECTION_BACKEND_CRAZY;
|
||||
self->errormsg = "Unexpected protocol character from backend (send_function, args)";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
|
||||
mylog("send_function: error - %s\n", self->errormsg);
|
||||
return FALSE;
|
||||
@ -1690,7 +1707,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
|
||||
case 'E':
|
||||
SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
|
||||
self->errormsg = msgbuffer;
|
||||
CC_on_abort(self, FALSE);
|
||||
CC_on_abort(self, 0);
|
||||
mylog("send_function(G): 'E' - %s\n", self->errormsg);
|
||||
qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
|
||||
|
||||
@ -1711,7 +1728,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_
|
||||
default:
|
||||
self->errornumber = CONNECTION_BACKEND_CRAZY;
|
||||
self->errormsg = "Unexpected protocol character from backend (send_function, result)";
|
||||
CC_on_abort(self, TRUE);
|
||||
CC_on_abort(self, NO_TRANS | CONN_DEAD);
|
||||
|
||||
mylog("send_function: error - %s\n", self->errormsg);
|
||||
return FALSE;
|
||||
|
@ -166,6 +166,7 @@ typedef struct
|
||||
char translation_option[SMALL_REGISTRY_LEN];
|
||||
char focus_password;
|
||||
char disallow_premature;
|
||||
char allow_keyset;
|
||||
char updatable_cursors;
|
||||
char lf_conversion;
|
||||
char true_is_minus1;
|
||||
@ -296,6 +297,7 @@ struct ConnectionClass_
|
||||
int ccsc;
|
||||
int be_pid; /* pid returned by backend */
|
||||
int be_key; /* auth code needed to send cancel */
|
||||
UInt4 isolation;
|
||||
};
|
||||
|
||||
|
||||
@ -339,11 +341,15 @@ void CC_log_error(const char *func, const char *desc, const ConnectionClass *se
|
||||
int CC_get_max_query_len(const ConnectionClass *self);
|
||||
int CC_send_cancel_request(const ConnectionClass *conn);
|
||||
void CC_on_commit(ConnectionClass *conn);
|
||||
void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans);
|
||||
void CC_on_abort(ConnectionClass *conn, UDWORD opt);
|
||||
void ProcessRollback(ConnectionClass *conn, BOOL undo);
|
||||
|
||||
/* CC_send_query_options */
|
||||
/* CC_send_query options */
|
||||
#define CLEAR_RESULT_ON_ABORT 1L
|
||||
#define CREATE_KEYSET (1L << 1) /* create keyset for updatable curosrs */
|
||||
#define GO_INTO_TRANSACTION (1L << 2) /* issue begin in advance */
|
||||
#endif
|
||||
/* CC_on_abort options */
|
||||
#define NO_TRANS 1L
|
||||
#define CONN_DEAD (1L << 1) /* connection is no longer valid */
|
||||
|
||||
#endif /* __CONNECTION_H__ */
|
||||
|
@ -371,7 +371,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
|
||||
pbic = &opts->bindings[stmt->current_col];
|
||||
if (pbic->data_left == -2)
|
||||
pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
|
||||
* needed for ADO ? */
|
||||
* needed by ADO ? */
|
||||
if (pbic->data_left == 0)
|
||||
{
|
||||
if (pbic->ttlbuf != NULL)
|
||||
@ -984,6 +984,90 @@ inolog("2stime fr=%d\n", st.fr);
|
||||
#endif /* HAVE_LOCALE_H */
|
||||
break;
|
||||
|
||||
#if (ODBCVER >= 0x0300)
|
||||
case SQL_C_NUMERIC:
|
||||
#ifdef HAVE_LOCALE_H
|
||||
/* strcpy(saved_locale, setlocale(LC_ALL, NULL));
|
||||
setlocale(LC_ALL, "C"); not needed currently */
|
||||
#endif /* HAVE_LOCALE_H */
|
||||
{
|
||||
SQL_NUMERIC_STRUCT *ns;
|
||||
int i, nlen, bit, hval, tv, dig, sta, olen;
|
||||
char calv[SQL_MAX_NUMERIC_LEN * 3], *wv;
|
||||
BOOL dot_exist;
|
||||
|
||||
len = sizeof(SQL_NUMERIC_STRUCT);
|
||||
if (bind_size > 0)
|
||||
ns = (SQL_NUMERIC_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
|
||||
else
|
||||
ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
|
||||
for (wv = neut_str; *wv && isspace(*wv); wv++)
|
||||
;
|
||||
ns->sign = 1;
|
||||
if (*wv == '-')
|
||||
{
|
||||
ns->sign = 0;
|
||||
wv++;
|
||||
}
|
||||
else if (*wv == '+')
|
||||
wv++;
|
||||
while (*wv == '0') wv++;
|
||||
ns->precision = 0;
|
||||
ns->scale = 0;
|
||||
for (nlen = 0, dot_exist = FALSE;; wv++)
|
||||
{
|
||||
if (*wv == '.')
|
||||
{
|
||||
if (dot_exist)
|
||||
break;
|
||||
dot_exist = TRUE;
|
||||
}
|
||||
else if (!isdigit(*wv))
|
||||
break;
|
||||
else
|
||||
{
|
||||
if (dot_exist)
|
||||
ns->scale++;
|
||||
else
|
||||
ns->precision++;
|
||||
calv[nlen++] = *wv;
|
||||
}
|
||||
}
|
||||
memset(ns->val, 0, sizeof(ns->val));
|
||||
for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
|
||||
{
|
||||
for (dig = 0, i = sta; i < nlen; i++)
|
||||
{
|
||||
tv = dig * 10 + calv[i] - '0';
|
||||
dig = tv % 2;
|
||||
calv[i] = tv / 2 + '0';
|
||||
if (i == sta && tv < 2)
|
||||
sta++;
|
||||
}
|
||||
if (dig > 0)
|
||||
hval |= bit;
|
||||
bit <<= 1;
|
||||
if (bit >= (1L << 8))
|
||||
{
|
||||
ns->val[olen++] = hval;
|
||||
hval = 0;
|
||||
bit = 1L;
|
||||
if (olen >= SQL_MAX_NUMERIC_LEN - 1)
|
||||
{
|
||||
ns->scale = sta - ns->precision;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
|
||||
ns->val[olen++] = hval;
|
||||
}
|
||||
#ifdef HAVE_LOCALE_H
|
||||
/* setlocale(LC_ALL, saved_locale); */
|
||||
#endif /* HAVE_LOCALE_H */
|
||||
break;
|
||||
#endif /* ODBCVER */
|
||||
|
||||
case SQL_C_SSHORT:
|
||||
case SQL_C_SHORT:
|
||||
len = 2;
|
||||
@ -1179,6 +1263,8 @@ QP_initialize(QueryParse *q, const StatementClass *stmt)
|
||||
|
||||
#define FLGB_PRE_EXECUTING 1L
|
||||
#define FLGB_INACCURATE_RESULT (1L << 1)
|
||||
#define FLGB_CREATE_KEYSET (1L << 2)
|
||||
#define FLGB_KEYSET_DRIVEN (1L << 3)
|
||||
typedef struct _QueryBuild {
|
||||
char *query_statement;
|
||||
UInt4 str_size_limit;
|
||||
@ -1589,10 +1675,16 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
{
|
||||
if (stmt->parse_status == STMT_PARSE_NONE)
|
||||
parse_statement(stmt);
|
||||
/*if (stmt->parse_status != STMT_PARSE_COMPLETE)
|
||||
if (stmt->parse_status == STMT_PARSE_FATAL)
|
||||
{
|
||||
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
|
||||
else*/ if (!stmt->updatable)
|
||||
return SQL_ERROR;
|
||||
}
|
||||
else if (!stmt->updatable)
|
||||
{
|
||||
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
|
||||
stmt->options.cursor_type = SQL_CURSOR_STATIC;
|
||||
}
|
||||
else
|
||||
{
|
||||
qp->from_pos = stmt->from_pos;
|
||||
@ -1602,7 +1694,7 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
#else
|
||||
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
|
||||
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
|
||||
stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
|
||||
stmt->options.cursor_type = SQL_CURSOR_STATIC;
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
|
||||
/* If the application hasn't set a cursor name, then generate one */
|
||||
@ -1641,6 +1733,12 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
qp->flags |= FLGP_CURSOR_CHECK_OK;
|
||||
qp->declare_pos = qb->npos;
|
||||
}
|
||||
else if (SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
|
||||
{
|
||||
qb->flags |= FLGB_CREATE_KEYSET;
|
||||
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
|
||||
qb->flags |= FLGB_KEYSET_DRIVEN;
|
||||
}
|
||||
}
|
||||
|
||||
for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
|
||||
@ -1693,12 +1791,28 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
UInt4 npos = qb->load_stmt_len;
|
||||
|
||||
if (0 == npos)
|
||||
{
|
||||
npos = qb->npos;
|
||||
for (; npos > 0; npos--)
|
||||
{
|
||||
if (isspace(new_statement[npos - 1]))
|
||||
continue;
|
||||
if (';' != new_statement[npos - 1])
|
||||
break;
|
||||
}
|
||||
if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
|
||||
{
|
||||
qb->npos = npos;
|
||||
/* ----------
|
||||
* 1st query is for field information
|
||||
* 2nd query is keyset gathering
|
||||
*/
|
||||
CVT_APPEND_STR(qb, " where ctid = '(,)';select ctid, oid from ");
|
||||
CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, npos - qp->from_pos - 5);
|
||||
}
|
||||
}
|
||||
stmt->load_statement = malloc(npos + 1);
|
||||
memcpy(stmt->load_statement, new_statement, npos);
|
||||
if (stmt->load_statement[npos - 1] == ';')
|
||||
stmt->load_statement[npos - 1] = '\0';
|
||||
else
|
||||
memcpy(stmt->load_statement, qb->query_statement, npos);
|
||||
stmt->load_statement[npos] = '\0';
|
||||
}
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
@ -1732,7 +1846,14 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
|
||||
CVT_APPEND_STR(qb, ", CTID, OID ");
|
||||
}
|
||||
else if (qp->where_pos == (Int4) qp->opos)
|
||||
{
|
||||
qb->load_stmt_len = qb->npos;
|
||||
if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
|
||||
{
|
||||
CVT_APPEND_STR(qb, "where ctid = '(,)';select CTID, OID from ");
|
||||
CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, qp->where_pos - qp->from_pos - 5);
|
||||
}
|
||||
}
|
||||
#ifdef MULTIBYTE
|
||||
oldchar = encoded_byte_check(&qp->encstr, qp->opos);
|
||||
if (ENCODE_STATUS(qp->encstr) != 0)
|
||||
@ -1836,6 +1957,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
|
||||
{
|
||||
qp->flags |= FLGP_SELECT_INTO;
|
||||
qp->flags &= ~FLGP_CURSOR_CHECK_OK;
|
||||
qb->flags &= ~FLGB_KEYSET_DRIVEN;
|
||||
qp->statement_type = STMT_TYPE_CREATE;
|
||||
memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
|
||||
qb->npos -= qp->declare_pos;
|
||||
@ -1887,6 +2009,130 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
#if (ODBCVER >= 0x0300)
|
||||
static BOOL
|
||||
ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
|
||||
{
|
||||
static int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 29, 32, 34, 37, 39};
|
||||
Int4 i, j, k, ival, vlen, len, newlen;
|
||||
unsigned char calv[40];
|
||||
const unsigned char *val = (const unsigned char *) ns->val;
|
||||
BOOL next_figure;
|
||||
|
||||
if (0 == ns->precision)
|
||||
{
|
||||
strcpy(chrform, "0");
|
||||
return TRUE;
|
||||
}
|
||||
else if (ns->precision < prec[sizeof(Int4)])
|
||||
{
|
||||
for (i = 0, ival = 0; i < sizeof(Int4) && prec[i] <= ns->precision; i++)
|
||||
{
|
||||
ival += (val[i] << (8 * i)); /* ns->val is little endian */
|
||||
}
|
||||
if (0 == ns->scale)
|
||||
{
|
||||
if (0 == ns->sign)
|
||||
ival *= -1;
|
||||
sprintf(chrform, "%d", ival);
|
||||
}
|
||||
else if (ns->scale > 0)
|
||||
{
|
||||
Int4 i, div, o1val, o2val;
|
||||
|
||||
for (i = 0, div = 1; i < ns->scale; i++)
|
||||
div *= 10;
|
||||
o1val = ival / div;
|
||||
o2val = ival % div;
|
||||
if (0 == ns->sign)
|
||||
o1val *= -1;
|
||||
sprintf(chrform, "%d.%0.*d", o1val, ns->scale, o2val);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < SQL_MAX_NUMERIC_LEN && prec[i] <= ns->precision; i++)
|
||||
;
|
||||
vlen = i;
|
||||
len = 0;
|
||||
memset(calv, 0, sizeof(calv));
|
||||
for (i = vlen - 1; i >= 0; i--)
|
||||
{
|
||||
for (j = len - 1; j >= 0; j--)
|
||||
{
|
||||
if (!calv[j])
|
||||
continue;
|
||||
ival = (((Int4)calv[j]) << 8);
|
||||
calv[j] = (ival % 10);
|
||||
ival /= 10;
|
||||
calv[j + 1] += (ival % 10);
|
||||
ival /= 10;
|
||||
calv[j + 2] += (ival % 10);
|
||||
ival /= 10;
|
||||
calv[j + 3] += ival;
|
||||
for (k = j;; k++)
|
||||
{
|
||||
next_figure = FALSE;
|
||||
if (calv[k] > 0)
|
||||
{
|
||||
if (k >= len)
|
||||
len = k + 1;
|
||||
while (calv[k] > 9)
|
||||
{
|
||||
calv[k + 1]++;
|
||||
calv[k] -= 10;
|
||||
next_figure = TRUE;
|
||||
}
|
||||
}
|
||||
if (k >= j + 3 && !next_figure)
|
||||
break;
|
||||
}
|
||||
}
|
||||
ival = val[i];
|
||||
if (!ival)
|
||||
continue;
|
||||
calv[0] += (ival % 10);
|
||||
ival /= 10;
|
||||
calv[1] += (ival % 10);
|
||||
ival /= 10;
|
||||
calv[2] += ival;
|
||||
for (j = 0;; j++)
|
||||
{
|
||||
next_figure = FALSE;
|
||||
if (calv[j] > 0)
|
||||
{
|
||||
if (j >= len)
|
||||
len = j + 1;
|
||||
while (calv[j] > 9)
|
||||
{
|
||||
calv[j + 1]++;
|
||||
calv[j] -= 10;
|
||||
next_figure = TRUE;
|
||||
}
|
||||
}
|
||||
if (j >= 2 && !next_figure)
|
||||
break;
|
||||
}
|
||||
}
|
||||
newlen = 0;
|
||||
if (0 == ns->sign)
|
||||
chrform[newlen++] = '-';
|
||||
for (i = len - 1; i >= ns->scale; i--)
|
||||
chrform[newlen++] = calv[i] + '0';
|
||||
if (ns->scale > 0)
|
||||
{
|
||||
chrform[newlen++] = '.';
|
||||
for (; i >= 0; i--)
|
||||
chrform[newlen++] = calv[i] + '0';
|
||||
}
|
||||
chrform[newlen] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* ODBCVER */
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
ResolveOneParam(QueryBuild *qb)
|
||||
{
|
||||
@ -2138,6 +2384,11 @@ ResolveOneParam(QueryBuild *qb)
|
||||
break;
|
||||
|
||||
}
|
||||
#if (ODBCVER >= 0x0300)
|
||||
case SQL_C_NUMERIC:
|
||||
if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string))
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* error */
|
||||
qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
|
||||
@ -2336,13 +2587,13 @@ ResolveOneParam(QueryBuild *qb)
|
||||
if (buf)
|
||||
{
|
||||
cbuf[0] = '\'';
|
||||
my_strcpy(cbuf + 1, sizeof(cbuf) - 12, buf, used); /* 12 = 1('\'') +
|
||||
* strlen("'::numeric")
|
||||
my_strcpy(cbuf + 1, sizeof(cbuf) - 3, buf, used); /* 3 = 1('\'') +
|
||||
* strlen("'")
|
||||
* + 1('\0') */
|
||||
strcat(cbuf, "'::numeric");
|
||||
strcat(cbuf, "'");
|
||||
}
|
||||
else
|
||||
sprintf(cbuf, "'%s'::numeric", param_string);
|
||||
sprintf(cbuf, "'%s'", param_string);
|
||||
CVT_APPEND_STR(qb, cbuf);
|
||||
break;
|
||||
default: /* a numeric type or SQL_BIT */
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* Comments: See "notice.txt" for copyright and license information.
|
||||
*
|
||||
* $Id: descriptor.h,v 1.4 2002/04/10 08:18:54 inoue Exp $
|
||||
* $Id: descriptor.h,v 1.5 2002/05/22 05:51:03 inoue Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -20,6 +20,7 @@ typedef struct
|
||||
char schema[MAX_SCHEMA_LEN + 1];
|
||||
char name[MAX_TABLE_LEN + 1];
|
||||
char alias[MAX_TABLE_LEN + 1];
|
||||
char updatable;
|
||||
} TABLE_INFO;
|
||||
|
||||
typedef struct
|
||||
@ -41,6 +42,8 @@ typedef struct
|
||||
char name[MAX_COLUMN_LEN + 1];
|
||||
char alias[MAX_COLUMN_LEN + 1];
|
||||
} FIELD_INFO;
|
||||
Int4 FI_precision(const FIELD_INFO *);
|
||||
Int4 FI_scale(const FIELD_INFO *);
|
||||
|
||||
struct ARDFields_
|
||||
{
|
||||
|
@ -340,7 +340,7 @@ ds_optionsProc(HWND hdlg,
|
||||
CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature);
|
||||
CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion);
|
||||
CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1);
|
||||
CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->updatable_cursors);
|
||||
CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->allow_keyset);
|
||||
#ifndef DRIVER_CURSOR_IMPLEMENT
|
||||
EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE);
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
@ -382,7 +382,7 @@ ds_optionsProc(HWND hdlg,
|
||||
ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION);
|
||||
ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1);
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
ci->updatable_cursors = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
|
||||
ci->allow_keyset = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
|
||||
/* OID Options */
|
||||
@ -590,7 +590,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
|
||||
INI_LFCONVERSION,
|
||||
ci->lf_conversion,
|
||||
INI_UPDATABLECURSORS,
|
||||
ci->updatable_cursors,
|
||||
ci->allow_keyset,
|
||||
INI_DISALLOWPREMATURE,
|
||||
ci->disallow_premature,
|
||||
INI_TRUEISMINUS1,
|
||||
@ -601,7 +601,7 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
|
||||
unsigned long flag = 0;
|
||||
if (ci->disallow_premature)
|
||||
flag |= BIT_DISALLOWPREMATURE;
|
||||
if (ci->updatable_cursors)
|
||||
if (ci->allow_keyset)
|
||||
flag |= BIT_UPDATABLECURSORS;
|
||||
if (ci->lf_conversion)
|
||||
flag |= BIT_LFCONVERSION;
|
||||
@ -686,7 +686,7 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
|
||||
sscanf(value + 2, "%lx", &flag);
|
||||
}
|
||||
ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0);
|
||||
ci->updatable_cursors = (char)((flag & BIT_UPDATABLECURSORS) != 0);
|
||||
ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0);
|
||||
ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0);
|
||||
if (count < 4)
|
||||
return;
|
||||
@ -770,7 +770,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
|
||||
else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0)
|
||||
ci->disallow_premature = atoi(value);
|
||||
else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0)
|
||||
ci->updatable_cursors = atoi(value);
|
||||
ci->allow_keyset = atoi(value);
|
||||
else if (stricmp(attribute, INI_LFCONVERSION) == 0)
|
||||
ci->lf_conversion = atoi(value);
|
||||
else if (stricmp(attribute, INI_TRUEISMINUS1) == 0)
|
||||
@ -870,8 +870,8 @@ getDSNdefaults(ConnInfo *ci)
|
||||
|
||||
if (ci->disallow_premature < 0)
|
||||
ci->disallow_premature = DEFAULT_DISALLOWPREMATURE;
|
||||
if (ci->updatable_cursors < 0)
|
||||
ci->updatable_cursors = DEFAULT_UPDATABLECURSORS;
|
||||
if (ci->allow_keyset < 0)
|
||||
ci->allow_keyset = DEFAULT_UPDATABLECURSORS;
|
||||
if (ci->lf_conversion < 0)
|
||||
ci->lf_conversion = DEFAULT_LFCONVERSION;
|
||||
if (ci->true_is_minus1 < 0)
|
||||
@ -960,11 +960,11 @@ getDSNinfo(ConnInfo *ci, char overwrite)
|
||||
ci->disallow_premature = atoi(temp);
|
||||
}
|
||||
|
||||
if (ci->updatable_cursors < 0 || overwrite)
|
||||
if (ci->allow_keyset < 0 || overwrite)
|
||||
{
|
||||
SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI);
|
||||
if (temp[0])
|
||||
ci->updatable_cursors = atoi(temp);
|
||||
ci->allow_keyset = atoi(temp);
|
||||
}
|
||||
|
||||
if (ci->lf_conversion < 0 || overwrite)
|
||||
@ -1094,7 +1094,7 @@ writeDSNinfo(const ConnInfo *ci)
|
||||
INI_DISALLOWPREMATURE,
|
||||
temp,
|
||||
ODBC_INI);
|
||||
sprintf(temp, "%d", ci->updatable_cursors);
|
||||
sprintf(temp, "%d", ci->allow_keyset);
|
||||
SQLWritePrivateProfileString(DSN,
|
||||
INI_UPDATABLECURSORS,
|
||||
temp,
|
||||
|
@ -78,6 +78,12 @@ PGAPI_FreeEnv(HENV henv)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str)
|
||||
{
|
||||
strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
|
||||
}
|
||||
|
||||
#define DRVMNGRDIV 511
|
||||
/* Returns the next SQL error information. */
|
||||
RETCODE SQL_API
|
||||
@ -92,6 +98,7 @@ PGAPI_StmtError( HSTMT hstmt,
|
||||
{
|
||||
/* CC: return an error of a hstmt */
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
EnvironmentClass *env = (EnvironmentClass *) SC_get_conn(stmt)->henv;
|
||||
char *msg;
|
||||
int status;
|
||||
BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
|
||||
@ -173,120 +180,124 @@ PGAPI_StmtError( HSTMT hstmt,
|
||||
{
|
||||
/* now determine the SQLSTATE to be returned */
|
||||
case STMT_ROW_VERSION_CHANGED:
|
||||
strcpy(szSqlState, "01001");
|
||||
pg_sqlstate_set(env, szSqlState, "01001", "01001");
|
||||
/* data truncated */
|
||||
break;
|
||||
case STMT_TRUNCATED:
|
||||
strcpy(szSqlState, "01004");
|
||||
pg_sqlstate_set(env, szSqlState, "01004", "01004");
|
||||
/* data truncated */
|
||||
break;
|
||||
case STMT_INFO_ONLY:
|
||||
strcpy(szSqlState, "00000");
|
||||
pg_sqlstate_set(env, szSqlState, "00000", "0000");
|
||||
/* just information that is returned, no error */
|
||||
break;
|
||||
case STMT_BAD_ERROR:
|
||||
strcpy(szSqlState, "08S01");
|
||||
pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
|
||||
/* communication link failure */
|
||||
break;
|
||||
case STMT_CREATE_TABLE_ERROR:
|
||||
strcpy(szSqlState, "S0001");
|
||||
pg_sqlstate_set(env, szSqlState, "42S01", "S0001");
|
||||
/* table already exists */
|
||||
break;
|
||||
case STMT_STATUS_ERROR:
|
||||
case STMT_SEQUENCE_ERROR:
|
||||
strcpy(szSqlState, "S1010");
|
||||
pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
|
||||
/* Function sequence error */
|
||||
break;
|
||||
case STMT_NO_MEMORY_ERROR:
|
||||
strcpy(szSqlState, "S1001");
|
||||
pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
|
||||
/* memory allocation failure */
|
||||
break;
|
||||
case STMT_COLNUM_ERROR:
|
||||
strcpy(szSqlState, "S1002");
|
||||
pg_sqlstate_set(env, szSqlState, "07009", "S1002");
|
||||
/* invalid column number */
|
||||
break;
|
||||
case STMT_NO_STMTSTRING:
|
||||
strcpy(szSqlState, "S1001");
|
||||
pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
|
||||
/* having no stmtstring is also a malloc problem */
|
||||
break;
|
||||
case STMT_ERROR_TAKEN_FROM_BACKEND:
|
||||
strcpy(szSqlState, "S1000");
|
||||
pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
|
||||
/* general error */
|
||||
break;
|
||||
case STMT_INTERNAL_ERROR:
|
||||
strcpy(szSqlState, "S1000");
|
||||
pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
|
||||
/* general error */
|
||||
break;
|
||||
case STMT_FETCH_OUT_OF_RANGE:
|
||||
pg_sqlstate_set(env, szSqlState, "HY106", "S1106");
|
||||
break;
|
||||
|
||||
case STMT_ROW_OUT_OF_RANGE:
|
||||
strcpy(szSqlState, "S1107");
|
||||
pg_sqlstate_set(env, szSqlState, "HY107", "S1107");
|
||||
break;
|
||||
|
||||
case STMT_OPERATION_CANCELLED:
|
||||
strcpy(szSqlState, "S1008");
|
||||
pg_sqlstate_set(env, szSqlState, "HY008", "S1008");
|
||||
break;
|
||||
|
||||
case STMT_NOT_IMPLEMENTED_ERROR:
|
||||
strcpy(szSqlState, "S1C00"); /* == 'driver not
|
||||
pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00"); /* == 'driver not
|
||||
* capable' */
|
||||
break;
|
||||
case STMT_OPTION_OUT_OF_RANGE_ERROR:
|
||||
strcpy(szSqlState, "S1092");
|
||||
pg_sqlstate_set(env, szSqlState, "HY092", "S1092");
|
||||
break;
|
||||
case STMT_BAD_PARAMETER_NUMBER_ERROR:
|
||||
strcpy(szSqlState, "S1093");
|
||||
pg_sqlstate_set(env, szSqlState, "07009", "S1093");
|
||||
break;
|
||||
case STMT_INVALID_COLUMN_NUMBER_ERROR:
|
||||
strcpy(szSqlState, "S1002");
|
||||
pg_sqlstate_set(env, szSqlState, "07009", "S1002");
|
||||
break;
|
||||
case STMT_RESTRICTED_DATA_TYPE_ERROR:
|
||||
strcpy(szSqlState, "07006");
|
||||
pg_sqlstate_set(env, szSqlState, "07006", "07006");
|
||||
break;
|
||||
case STMT_INVALID_CURSOR_STATE_ERROR:
|
||||
strcpy(szSqlState, "24000");
|
||||
pg_sqlstate_set(env, szSqlState, "07005", "24000");
|
||||
break;
|
||||
case STMT_ERROR_IN_ROW:
|
||||
strcpy(szSqlState, "01S01");
|
||||
pg_sqlstate_set(env, szSqlState, "01S01", "01S01");
|
||||
break;
|
||||
case STMT_OPTION_VALUE_CHANGED:
|
||||
strcpy(szSqlState, "01S02");
|
||||
pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
|
||||
break;
|
||||
case STMT_POS_BEFORE_RECORDSET:
|
||||
strcpy(szSqlState, "01S06");
|
||||
pg_sqlstate_set(env, szSqlState, "01S06", "01S06");
|
||||
break;
|
||||
case STMT_INVALID_CURSOR_NAME:
|
||||
strcpy(szSqlState, "34000");
|
||||
pg_sqlstate_set(env, szSqlState, "34000", "34000");
|
||||
break;
|
||||
case STMT_NO_CURSOR_NAME:
|
||||
strcpy(szSqlState, "S1015");
|
||||
pg_sqlstate_set(env, szSqlState, "S1015", "S1015");
|
||||
break;
|
||||
case STMT_INVALID_ARGUMENT_NO:
|
||||
strcpy(szSqlState, "S1009");
|
||||
pg_sqlstate_set(env, szSqlState, "HY024", "S1009");
|
||||
/* invalid argument value */
|
||||
break;
|
||||
case STMT_INVALID_CURSOR_POSITION:
|
||||
strcpy(szSqlState, "S1109");
|
||||
pg_sqlstate_set(env, szSqlState, "HY109", "S1109");
|
||||
break;
|
||||
case STMT_RETURN_NULL_WITHOUT_INDICATOR:
|
||||
strcpy(szSqlState, "22002");
|
||||
pg_sqlstate_set(env, szSqlState, "22002", "22002");
|
||||
break;
|
||||
case STMT_VALUE_OUT_OF_RANGE:
|
||||
strcpy(szSqlState, "22003");
|
||||
pg_sqlstate_set(env, szSqlState, "HY019", "22003");
|
||||
break;
|
||||
case STMT_OPERATION_INVALID:
|
||||
strcpy(szSqlState, "S1011");
|
||||
pg_sqlstate_set(env, szSqlState, "HY011", "S1011");
|
||||
break;
|
||||
case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
|
||||
strcpy(szSqlState, "HY091");
|
||||
pg_sqlstate_set(env, szSqlState, "HY091", "HY091");
|
||||
break;
|
||||
case STMT_INVALID_OPTION_IDENTIFIER:
|
||||
strcpy(szSqlState, "HY092");
|
||||
pg_sqlstate_set(env, szSqlState, "HY092", "HY092");
|
||||
break;
|
||||
case STMT_OPTION_NOT_FOR_THE_DRIVER:
|
||||
strcpy(szSqlState, "HYC00");
|
||||
pg_sqlstate_set(env, szSqlState, "HYC00", "HYC00");
|
||||
break;
|
||||
case STMT_EXEC_ERROR:
|
||||
default:
|
||||
strcpy(szSqlState, "S1000");
|
||||
pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
|
||||
/* also a general error */
|
||||
break;
|
||||
}
|
||||
@ -314,6 +325,7 @@ PGAPI_ConnectError( HDBC hdbc,
|
||||
UWORD flag)
|
||||
{
|
||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||
EnvironmentClass *env = (EnvironmentClass *) conn->henv;
|
||||
char *msg;
|
||||
int status;
|
||||
BOOL once_again = FALSE;
|
||||
@ -357,43 +369,43 @@ PGAPI_ConnectError( HDBC hdbc,
|
||||
{
|
||||
case STMT_OPTION_VALUE_CHANGED:
|
||||
case CONN_OPTION_VALUE_CHANGED:
|
||||
strcpy(szSqlState, "01S02");
|
||||
pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
|
||||
break;
|
||||
case STMT_TRUNCATED:
|
||||
case CONN_TRUNCATED:
|
||||
strcpy(szSqlState, "01004");
|
||||
pg_sqlstate_set(env, szSqlState, "01004", "01004");
|
||||
/* data truncated */
|
||||
break;
|
||||
case CONN_INIREAD_ERROR:
|
||||
strcpy(szSqlState, "IM002");
|
||||
pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
|
||||
/* data source not found */
|
||||
break;
|
||||
case CONNECTION_SERVER_NOT_REACHED:
|
||||
case CONN_OPENDB_ERROR:
|
||||
strcpy(szSqlState, "08001");
|
||||
pg_sqlstate_set(env, szSqlState, "08001", "08001");
|
||||
/* unable to connect to data source */
|
||||
break;
|
||||
case CONN_INVALID_AUTHENTICATION:
|
||||
case CONN_AUTH_TYPE_UNSUPPORTED:
|
||||
strcpy(szSqlState, "28000");
|
||||
pg_sqlstate_set(env, szSqlState, "28000", "28000");
|
||||
break;
|
||||
case CONN_STMT_ALLOC_ERROR:
|
||||
strcpy(szSqlState, "S1001");
|
||||
pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
|
||||
/* memory allocation failure */
|
||||
break;
|
||||
case CONN_IN_USE:
|
||||
strcpy(szSqlState, "S1000");
|
||||
pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
|
||||
/* general error */
|
||||
break;
|
||||
case CONN_UNSUPPORTED_OPTION:
|
||||
strcpy(szSqlState, "IM001");
|
||||
pg_sqlstate_set(env, szSqlState, "IM001", "IM001");
|
||||
/* driver does not support this function */
|
||||
case CONN_INVALID_ARGUMENT_NO:
|
||||
strcpy(szSqlState, "S1009");
|
||||
pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
|
||||
/* invalid argument value */
|
||||
break;
|
||||
case CONN_TRANSACT_IN_PROGRES:
|
||||
strcpy(szSqlState, "S1010");
|
||||
pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
|
||||
|
||||
/*
|
||||
* when the user tries to switch commit mode in a
|
||||
@ -402,21 +414,21 @@ PGAPI_ConnectError( HDBC hdbc,
|
||||
/* -> function sequence error */
|
||||
break;
|
||||
case CONN_NO_MEMORY_ERROR:
|
||||
strcpy(szSqlState, "S1001");
|
||||
pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
|
||||
break;
|
||||
case CONN_NOT_IMPLEMENTED_ERROR:
|
||||
case STMT_NOT_IMPLEMENTED_ERROR:
|
||||
strcpy(szSqlState, "S1C00");
|
||||
pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
|
||||
break;
|
||||
case STMT_RETURN_NULL_WITHOUT_INDICATOR:
|
||||
strcpy(szSqlState, "22002");
|
||||
pg_sqlstate_set(env, szSqlState, "22002", "22002");
|
||||
break;
|
||||
case CONN_VALUE_OUT_OF_RANGE:
|
||||
case STMT_VALUE_OUT_OF_RANGE:
|
||||
strcpy(szSqlState, "22003");
|
||||
pg_sqlstate_set(env, szSqlState, "HY019", "22003");
|
||||
break;
|
||||
default:
|
||||
strcpy(szSqlState, "S1000");
|
||||
pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
|
||||
/* general error */
|
||||
break;
|
||||
}
|
||||
@ -455,7 +467,7 @@ PGAPI_EnvError( HENV henv,
|
||||
mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
|
||||
|
||||
if (NULL != szSqlState)
|
||||
strcpy(szSqlState, "00000");
|
||||
pg_sqlstate_set(env, szSqlState, "00000", "00000");
|
||||
if (NULL != pcbErrorMsg)
|
||||
*pcbErrorMsg = 0;
|
||||
if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
|
||||
@ -478,10 +490,10 @@ PGAPI_EnvError( HENV henv,
|
||||
{
|
||||
case ENV_ALLOC_ERROR:
|
||||
/* memory allocation failure */
|
||||
strcpy(szSqlState, "S1001");
|
||||
pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
|
||||
break;
|
||||
default:
|
||||
strcpy(szSqlState, "S1000");
|
||||
pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
|
||||
/* general error */
|
||||
break;
|
||||
}
|
||||
|
@ -212,6 +212,7 @@ PGAPI_Execute(
|
||||
int i,
|
||||
retval, start_row, end_row;
|
||||
int cursor_type, scroll_concurrency;
|
||||
QResultClass *res;
|
||||
|
||||
mylog("%s: entering...\n", func);
|
||||
|
||||
@ -403,6 +404,23 @@ next_param_row:
|
||||
{
|
||||
if (ipdopts->param_processed_ptr)
|
||||
(*ipdopts->param_processed_ptr)++;
|
||||
/* special handling of result for keyset driven cursors */
|
||||
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
|
||||
SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
|
||||
{
|
||||
QResultClass *kres;
|
||||
|
||||
res = SC_get_Result(stmt);
|
||||
if (kres = res->next, kres)
|
||||
{
|
||||
kres->fields = res->fields;
|
||||
res->fields = NULL;
|
||||
kres->num_fields = res->num_fields;
|
||||
res->next = NULL;
|
||||
QR_Destructor(res);
|
||||
SC_set_Result(stmt, kres);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (ODBCVER >= 0x0300)
|
||||
if (ipdopts->param_status_ptr)
|
||||
@ -440,7 +458,7 @@ next_param_row:
|
||||
BOOL in_trans = CC_is_in_trans(conn);
|
||||
BOOL issued_begin = FALSE,
|
||||
begin_included = FALSE;
|
||||
QResultClass *res, *curres;
|
||||
QResultClass *curres;
|
||||
|
||||
if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
|
||||
begin_included = TRUE;
|
||||
@ -474,7 +492,9 @@ next_param_row:
|
||||
stmt->status = STMT_FINISHED;
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
else if (stmt->options.cursor_type != cursor_type ||
|
||||
if (res = SC_get_Curres(stmt), res)
|
||||
stmt->diag_row_count = res->recent_processed_row_count;
|
||||
if (stmt->options.cursor_type != cursor_type ||
|
||||
stmt->options.scroll_concurrency != scroll_concurrency)
|
||||
{
|
||||
stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
|
||||
@ -548,7 +568,7 @@ PGAPI_Transact(
|
||||
if (!res)
|
||||
{
|
||||
/* error msg will be in the connection */
|
||||
CC_on_abort(conn, TRUE);
|
||||
CC_on_abort(conn, NO_TRANS);
|
||||
CC_log_error(func, "", conn);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
@ -558,7 +578,7 @@ PGAPI_Transact(
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
CC_on_abort(conn, TRUE);
|
||||
CC_on_abort(conn, NO_TRANS);
|
||||
CC_log_error(func, "", conn);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
@ -210,7 +210,10 @@ PGAPI_GetInfo(
|
||||
|
||||
case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
|
||||
len = 4;
|
||||
value = SQL_TXN_READ_COMMITTED; /* SQL_TXN_SERIALIZABLE; */
|
||||
if (PG_VERSION_LT(conn, 6.5))
|
||||
value = SQL_TXN_SERIALIZABLE;
|
||||
else
|
||||
value = SQL_TXN_READ_COMMITTED;
|
||||
break;
|
||||
|
||||
case SQL_DRIVER_NAME: /* ODBC 1.0 */
|
||||
@ -505,7 +508,7 @@ PGAPI_GetInfo(
|
||||
|
||||
case SQL_POS_OPERATIONS: /* ODBC 2.0 */
|
||||
len = 4;
|
||||
value = ci->drivers.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH);
|
||||
value = (SQL_POS_POSITION | SQL_POS_REFRESH);
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
if (ci->updatable_cursors)
|
||||
value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
|
||||
@ -557,32 +560,29 @@ PGAPI_GetInfo(
|
||||
* Driver doesn't support keyset-driven or mixed cursors, so
|
||||
* not much point in saying row updates are supported
|
||||
*/
|
||||
p = (ci->drivers.lie || ci->updatable_cursors) ? "Y" : "N";
|
||||
p = (ci->updatable_cursors) ? "Y" : "N";
|
||||
break;
|
||||
|
||||
case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
|
||||
len = 4;
|
||||
value = ci->drivers.lie ? (SQL_SCCO_READ_ONLY |
|
||||
SQL_SCCO_LOCK |
|
||||
SQL_SCCO_OPT_ROWVER |
|
||||
SQL_SCCO_OPT_VALUES) :
|
||||
(SQL_SCCO_READ_ONLY);
|
||||
value = SQL_SCCO_READ_ONLY;
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
if (ci->updatable_cursors)
|
||||
value |= SQL_SCCO_OPT_ROWVER;
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
if (ci->drivers.lie)
|
||||
value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
|
||||
break;
|
||||
|
||||
case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
|
||||
len = 4;
|
||||
value = ci->drivers.lie ? (SQL_SO_FORWARD_ONLY |
|
||||
SQL_SO_STATIC |
|
||||
SQL_SO_KEYSET_DRIVEN |
|
||||
SQL_SO_DYNAMIC |
|
||||
SQL_SO_MIXED)
|
||||
: (ci->drivers.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC));
|
||||
value = SQL_SO_FORWARD_ONLY;
|
||||
if (!ci->drivers.use_declarefetch)
|
||||
value |= SQL_SO_STATIC;
|
||||
if (ci->updatable_cursors)
|
||||
value |= 0; /* SQL_SO_KEYSET_DRIVEN in the furure */
|
||||
value |= SQL_SO_KEYSET_DRIVEN;
|
||||
if (ci->drivers.lie)
|
||||
value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
|
||||
break;
|
||||
|
||||
case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
|
||||
@ -602,7 +602,7 @@ PGAPI_GetInfo(
|
||||
|
||||
case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
|
||||
len = 4;
|
||||
value = ci->drivers.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0;
|
||||
value = 0;
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
if (ci->updatable_cursors)
|
||||
value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
|
||||
@ -666,7 +666,12 @@ PGAPI_GetInfo(
|
||||
|
||||
case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
|
||||
len = 4;
|
||||
value = SQL_TXN_READ_COMMITTED; /* SQL_TXN_SERIALIZABLE; */
|
||||
if (PG_VERSION_LT(conn, 6.5))
|
||||
value = SQL_TXN_SERIALIZABLE;
|
||||
else if (PG_VERSION_GE(conn, 7.1))
|
||||
value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
|
||||
else
|
||||
value = SQL_TXN_READ_COMMITTED;
|
||||
break;
|
||||
|
||||
case SQL_UNION: /* ODBC 2.0 */
|
||||
@ -2097,7 +2102,7 @@ PGAPI_SpecialColumns(
|
||||
RETCODE result;
|
||||
char relhasrules[MAX_INFO_STRING];
|
||||
|
||||
mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
|
||||
mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType);
|
||||
|
||||
if (!stmt)
|
||||
{
|
||||
@ -2221,6 +2226,43 @@ PGAPI_SpecialColumns(
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* use the oid value for the rowid */
|
||||
if (fColType == SQL_BEST_ROWID)
|
||||
{
|
||||
row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
|
||||
|
||||
set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
|
||||
set_tuplefield_string(&row->tuple[1], "oid");
|
||||
set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID));
|
||||
set_tuplefield_string(&row->tuple[3], "OID");
|
||||
set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
|
||||
set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
|
||||
|
||||
QR_add_tuple(res, row);
|
||||
|
||||
}
|
||||
else if (fColType == SQL_ROWVER)
|
||||
{
|
||||
Int2 the_type = PG_TYPE_TID;
|
||||
|
||||
row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
|
||||
|
||||
set_tuplefield_null(&row->tuple[0]);
|
||||
set_tuplefield_string(&row->tuple[1], "ctid");
|
||||
set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
|
||||
set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
|
||||
set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
|
||||
set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
|
||||
set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
|
||||
|
||||
QR_add_tuple(res, row);
|
||||
}
|
||||
}
|
||||
|
||||
stmt->status = STMT_FINISHED;
|
||||
stmt->currTuple = -1;
|
||||
@ -3124,7 +3166,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
|
||||
{
|
||||
if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
|
||||
{
|
||||
if (QR_get_num_tuples(res) > 0)
|
||||
if (QR_get_num_backend_tuples(res) > 0)
|
||||
conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
|
||||
QR_Destructor(res);
|
||||
}
|
||||
@ -3140,7 +3182,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
|
||||
relid, serverColumnName);
|
||||
if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
|
||||
{
|
||||
if (QR_get_num_tuples(res) > 0)
|
||||
if (QR_get_num_backend_tuples(res) > 0)
|
||||
{
|
||||
strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
|
||||
}
|
||||
@ -3165,7 +3207,7 @@ getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName,
|
||||
sprintf(query, "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
|
||||
if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
|
||||
{
|
||||
if (QR_get_num_tuples(res) > 0)
|
||||
if (QR_get_num_backend_tuples(res) > 0)
|
||||
{
|
||||
ret = strdup(QR_get_value_backend_row(res, 0, 0));
|
||||
*nameAlloced = TRUE;
|
||||
@ -4135,7 +4177,7 @@ PGAPI_Procedures(
|
||||
* The following seems the simplest implementation
|
||||
*/
|
||||
if (conn->schema_support)
|
||||
strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", case when nspname = 'PUBLIC' then ''::text else nspname end as " "PROCEDURE_SCHEM" ","
|
||||
strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", nspname as " "PROCEDURE_SCHEM" ","
|
||||
" proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
|
||||
" '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
|
||||
" '' as " "REMARKS" ","
|
||||
@ -4204,7 +4246,7 @@ usracl_auth(char *usracl, const char *auth)
|
||||
static void
|
||||
useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
|
||||
{
|
||||
int usercount = QR_get_num_tuples(allures), i, addcnt = 0;
|
||||
int usercount = QR_get_num_backend_tuples(allures), i, addcnt = 0;
|
||||
|
||||
mylog("user=%s auth=%s\n", user, auth);
|
||||
if (user[0])
|
||||
@ -4315,7 +4357,7 @@ PGAPI_TablePrivileges(
|
||||
return SQL_ERROR;
|
||||
}
|
||||
strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
|
||||
tablecount = QR_get_num_tuples(res);
|
||||
tablecount = QR_get_num_backend_tuples(res);
|
||||
if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures)
|
||||
{
|
||||
QR_Destructor(res);
|
||||
@ -4323,7 +4365,7 @@ PGAPI_TablePrivileges(
|
||||
stmt->errormsg = "PGAPI_TablePrivileges query error";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
usercount = QR_get_num_tuples(allures);
|
||||
usercount = QR_get_num_backend_tuples(allures);
|
||||
useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
|
||||
for (i = 0; i < tablecount; i++)
|
||||
{
|
||||
|
@ -38,12 +38,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
|
||||
|
||||
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
|
||||
len = 4;
|
||||
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
|
||||
SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
|
||||
value = SQL_CA1_NEXT; /* others aren't allowed in ODBC spec */
|
||||
break;
|
||||
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
|
||||
len = 4;
|
||||
value = 0;
|
||||
value = SQL_CA2_READ_ONLY_CONCURRENCY;
|
||||
break;
|
||||
case SQL_KEYSET_CURSOR_ATTRIBUTES1:
|
||||
len = 4;
|
||||
@ -71,6 +70,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
|
||||
value = 0;
|
||||
if (ci->updatable_cursors || ci->drivers.lie)
|
||||
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
|
||||
/*| SQL_CA2_CRC_APPROXIMATE*/
|
||||
| SQL_CA2_CRC_EXACT
|
||||
| SQL_CA2_SENSITIVITY_DELETIONS
|
||||
| SQL_CA2_SENSITIVITY_UPDATES
|
||||
/* | SQL_CA2_SENSITIVITY_ADDITIONS */
|
||||
@ -85,8 +86,6 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
|
||||
| SQL_CA2_MAX_ROWS_UPDATE
|
||||
| SQL_CA2_MAX_ROWS_CATALOG
|
||||
| SQL_CA2_MAX_ROWS_AFFECTS_ALL
|
||||
| SQL_CA2_CRC_EXACT
|
||||
| SQL_CA2_CRC_APPROXIMATE
|
||||
| SQL_CA2_SIMULATE_NON_UNIQUE
|
||||
| SQL_CA2_SIMULATE_TRY_UNIQUE
|
||||
| SQL_CA2_SIMULATE_UNIQUE
|
||||
@ -101,6 +100,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
|
||||
| SQL_CA1_POS_REFRESH;
|
||||
if (ci->updatable_cursors)
|
||||
value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
|
||||
| SQL_CA1_BULK_ADD
|
||||
);
|
||||
break;
|
||||
case SQL_STATIC_CURSOR_ATTRIBUTES2:
|
||||
@ -108,6 +108,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
|
||||
value = SQL_CA2_READ_ONLY_CONCURRENCY;
|
||||
if (ci->updatable_cursors)
|
||||
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
|
||||
| SQL_CA2_CRC_EXACT
|
||||
/* | SQL_CA2_SENSITIVITY_ADDITIONS
|
||||
| SQL_CA2_SENSITIVITY_DELETIONS
|
||||
| SQL_CA2_SENSITIVITY_UPDATES */
|
||||
@ -117,6 +118,8 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
|
||||
case SQL_ODBC_INTERFACE_CONFORMANCE:
|
||||
len = 4;
|
||||
value = SQL_OIC_CORE;
|
||||
if (ci->drivers.lie)
|
||||
value = SQL_OIC_LEVEL2;
|
||||
break;
|
||||
case SQL_ACTIVE_ENVIRONMENTS:
|
||||
len = 2;
|
||||
|
@ -105,7 +105,7 @@ mylog(char *fmt,...)
|
||||
if (!LOGFP)
|
||||
{
|
||||
generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
|
||||
LOGFP = fopen(filebuf, PG_BINARY_W);
|
||||
LOGFP = fopen(filebuf, PG_BINARY_A);
|
||||
setbuf(LOGFP, NULL);
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ qlog(char *fmt,...)
|
||||
if (!LOGFP)
|
||||
{
|
||||
generate_filename(QLOGDIR, QLOGFILE, filebuf);
|
||||
LOGFP = fopen(filebuf, PG_BINARY_W);
|
||||
LOGFP = fopen(filebuf, PG_BINARY_A);
|
||||
setbuf(LOGFP, NULL);
|
||||
}
|
||||
|
||||
@ -284,8 +284,13 @@ schema_strcat(char *buf, const char *fmt, const char *s, int len, const char *tb
|
||||
{
|
||||
if (!s || 0 == len)
|
||||
{
|
||||
if (tbname && (tbnmlen > 0 || tbnmlen == SQL_NTS))
|
||||
return my_strcat(buf, fmt, "public", 6);
|
||||
/*
|
||||
* I can find no appropriate way to find
|
||||
* the CURRENT SCHEMA. If you are lucky
|
||||
* you can get expected result.
|
||||
*/
|
||||
/***** if (tbname && (tbnmlen > 0 || tbnmlen == SQL_NTS))
|
||||
return my_strcat(buf, fmt, "public", 6); *****/
|
||||
return NULL;
|
||||
}
|
||||
return my_strcat(buf, fmt, s, len);
|
||||
|
@ -77,10 +77,12 @@ extern void qlog(char *fmt,...);
|
||||
#define PG_BINARY O_BINARY
|
||||
#define PG_BINARY_R "rb"
|
||||
#define PG_BINARY_W "wb"
|
||||
#define PG_BINARY_A "ab"
|
||||
#else
|
||||
#define PG_BINARY 0
|
||||
#define PG_BINARY_R "r"
|
||||
#define PG_BINARY_W "w"
|
||||
#define PG_BINARY_A "a"
|
||||
#endif
|
||||
|
||||
|
||||
@ -91,7 +93,8 @@ char *make_string(const char *s, int len, char *buf);
|
||||
char *my_strcat(char *buf, const char *fmt, const char *s, int len);
|
||||
char *schema_strcat(char *buf, const char *fmt, const char *s, int len,
|
||||
const char *, int);
|
||||
#define GET_SCHEMA_NAME(nspname) (stricmp(nspname, "public") ? nspname : "")
|
||||
/* #define GET_SCHEMA_NAME(nspname) (stricmp(nspname, "public") ? nspname : "") */
|
||||
#define GET_SCHEMA_NAME(nspname) (nspname)
|
||||
|
||||
/* defines for return value of my_strcpy */
|
||||
#define STRCPY_SUCCESS 1
|
||||
|
@ -54,6 +54,7 @@ SQLAllocStmt(HDBC ConnectionHandle,
|
||||
HSTMT *StatementHandle)
|
||||
{
|
||||
mylog("[SQLAllocStmt]");
|
||||
CC_clear_error((ConnectionClass *) ConnectionHandle);
|
||||
return PGAPI_AllocStmt(ConnectionHandle, StatementHandle);
|
||||
}
|
||||
|
||||
@ -64,6 +65,7 @@ SQLBindCol(HSTMT StatementHandle,
|
||||
SQLINTEGER *StrLen_or_Ind)
|
||||
{
|
||||
mylog("[SQLBindCol]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_BindCol(StatementHandle, ColumnNumber,
|
||||
TargetType, TargetValue, BufferLength, StrLen_or_Ind);
|
||||
}
|
||||
@ -72,6 +74,7 @@ RETCODE SQL_API
|
||||
SQLCancel(HSTMT StatementHandle)
|
||||
{
|
||||
mylog("[SQLCancel]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_Cancel(StatementHandle);
|
||||
}
|
||||
|
||||
@ -83,6 +86,7 @@ SQLColumns(HSTMT StatementHandle,
|
||||
SQLCHAR *ColumnName, SQLSMALLINT NameLength4)
|
||||
{
|
||||
mylog("[SQLColumns]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_Columns(StatementHandle, CatalogName, NameLength1,
|
||||
SchemaName, NameLength2, TableName, NameLength3,
|
||||
ColumnName, NameLength4, 0);
|
||||
@ -96,6 +100,7 @@ SQLConnect(HDBC ConnectionHandle,
|
||||
SQLCHAR *Authentication, SQLSMALLINT NameLength3)
|
||||
{
|
||||
mylog("[SQLConnect]");
|
||||
CC_clear_error((ConnectionClass *) ConnectionHandle);
|
||||
return PGAPI_Connect(ConnectionHandle, ServerName, NameLength1,
|
||||
UserName, NameLength2, Authentication, NameLength3);
|
||||
}
|
||||
@ -111,6 +116,7 @@ SQLDriverConnect(HDBC hdbc,
|
||||
UWORD fDriverCompletion)
|
||||
{
|
||||
mylog("[SQLDriverConnect]");
|
||||
CC_clear_error((ConnectionClass *) hdbc);
|
||||
return PGAPI_DriverConnect(hdbc, hwnd, szConnStrIn, cbConnStrIn,
|
||||
szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
|
||||
}
|
||||
@ -124,6 +130,7 @@ SQLBrowseConnect(
|
||||
SQLSMALLINT *pcbConnStrOut)
|
||||
{
|
||||
mylog("[SQLBrowseConnect]");
|
||||
CC_clear_error((ConnectionClass *) hdbc);
|
||||
return PGAPI_BrowseConnect(hdbc, szConnStrIn, cbConnStrIn,
|
||||
szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
|
||||
}
|
||||
@ -153,6 +160,7 @@ SQLDescribeCol(HSTMT StatementHandle,
|
||||
SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
|
||||
{
|
||||
mylog("[SQLDescribeCol]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_DescribeCol(StatementHandle, ColumnNumber,
|
||||
ColumnName, BufferLength, NameLength,
|
||||
DataType, ColumnSize, DecimalDigits, Nullable);
|
||||
@ -162,6 +170,7 @@ RETCODE SQL_API
|
||||
SQLDisconnect(HDBC ConnectionHandle)
|
||||
{
|
||||
mylog("[SQLDisconnect]");
|
||||
CC_clear_error((ConnectionClass *) ConnectionHandle);
|
||||
return PGAPI_Disconnect(ConnectionHandle);
|
||||
}
|
||||
|
||||
@ -183,6 +192,7 @@ SQLExecDirect(HSTMT StatementHandle,
|
||||
SQLCHAR *StatementText, SQLINTEGER TextLength)
|
||||
{
|
||||
mylog("[SQLExecDirect]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_ExecDirect(StatementHandle, StatementText, TextLength);
|
||||
}
|
||||
|
||||
@ -190,6 +200,7 @@ RETCODE SQL_API
|
||||
SQLExecute(HSTMT StatementHandle)
|
||||
{
|
||||
mylog("[SQLExecute]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_Execute(StatementHandle);
|
||||
}
|
||||
|
||||
@ -202,6 +213,7 @@ SQLFetch(HSTMT StatementHandle)
|
||||
StatementClass *stmt = (StatementClass *) StatementHandle;
|
||||
ConnectionClass *conn = SC_get_conn(stmt);
|
||||
|
||||
SC_clear_error(stmt);
|
||||
if (conn->driver_version >= 0x0300)
|
||||
{
|
||||
IRDFields *irdopts = SC_get_IRD(stmt);
|
||||
@ -210,7 +222,7 @@ SQLFetch(HSTMT StatementHandle)
|
||||
|
||||
mylog("[[%s]]", func);
|
||||
return PGAPI_ExtendedFetch(StatementHandle, SQL_FETCH_NEXT, 0,
|
||||
pcRow, rowStatusArray);
|
||||
pcRow, rowStatusArray, 0);
|
||||
}
|
||||
#endif
|
||||
mylog("[%s]", func);
|
||||
@ -244,6 +256,7 @@ SQLGetConnectOption(HDBC ConnectionHandle,
|
||||
SQLUSMALLINT Option, PTR Value)
|
||||
{
|
||||
mylog("[SQLGetConnectOption]");
|
||||
CC_clear_error((ConnectionClass *) ConnectionHandle);
|
||||
return PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
|
||||
}
|
||||
RETCODE SQL_API
|
||||
@ -252,6 +265,7 @@ SQLGetCursorName(HSTMT StatementHandle,
|
||||
SQLSMALLINT *NameLength)
|
||||
{
|
||||
mylog("[SQLGetCursorName]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_GetCursorName(StatementHandle, CursorName, BufferLength,
|
||||
NameLength);
|
||||
}
|
||||
@ -263,6 +277,7 @@ SQLGetData(HSTMT StatementHandle,
|
||||
SQLINTEGER *StrLen_or_Ind)
|
||||
{
|
||||
mylog("[SQLGetData]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_GetData(StatementHandle, ColumnNumber, TargetType,
|
||||
TargetValue, BufferLength, StrLen_or_Ind);
|
||||
}
|
||||
@ -272,6 +287,7 @@ SQLGetFunctions(HDBC ConnectionHandle,
|
||||
SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported)
|
||||
{
|
||||
mylog("[SQLGetFunctions]");
|
||||
CC_clear_error((ConnectionClass *) ConnectionHandle);
|
||||
#if (ODBCVER >= 0x0300)
|
||||
if (FunctionId == SQL_API_ODBC3_ALL_FUNCTIONS)
|
||||
return PGAPI_GetFunctions30(ConnectionHandle, FunctionId, Supported);
|
||||
@ -315,6 +331,7 @@ SQLGetStmtOption(HSTMT StatementHandle,
|
||||
SQLUSMALLINT Option, PTR Value)
|
||||
{
|
||||
mylog("[SQLGetStmtOption]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_GetStmtOption(StatementHandle, Option, Value);
|
||||
}
|
||||
|
||||
@ -323,6 +340,7 @@ SQLGetTypeInfo(HSTMT StatementHandle,
|
||||
SQLSMALLINT DataType)
|
||||
{
|
||||
mylog("[SQLGetTypeInfo]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_GetTypeInfo(StatementHandle, DataType);
|
||||
}
|
||||
|
||||
@ -331,6 +349,7 @@ SQLNumResultCols(HSTMT StatementHandle,
|
||||
SQLSMALLINT *ColumnCount)
|
||||
{
|
||||
mylog("[SQLNumResultCols]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_NumResultCols(StatementHandle, ColumnCount);
|
||||
}
|
||||
|
||||
@ -339,6 +358,7 @@ SQLParamData(HSTMT StatementHandle,
|
||||
PTR *Value)
|
||||
{
|
||||
mylog("[SQLParamData]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_ParamData(StatementHandle, Value);
|
||||
}
|
||||
|
||||
@ -347,6 +367,7 @@ SQLPrepare(HSTMT StatementHandle,
|
||||
SQLCHAR *StatementText, SQLINTEGER TextLength)
|
||||
{
|
||||
mylog("[SQLPrepare]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_Prepare(StatementHandle, StatementText, TextLength);
|
||||
}
|
||||
|
||||
@ -355,6 +376,7 @@ SQLPutData(HSTMT StatementHandle,
|
||||
PTR Data, SQLINTEGER StrLen_or_Ind)
|
||||
{
|
||||
mylog("[SQLPutData]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_PutData(StatementHandle, Data, StrLen_or_Ind);
|
||||
}
|
||||
|
||||
@ -363,6 +385,7 @@ SQLRowCount(HSTMT StatementHandle,
|
||||
SQLINTEGER *RowCount)
|
||||
{
|
||||
mylog("[SQLRowCount]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_RowCount(StatementHandle, RowCount);
|
||||
}
|
||||
|
||||
@ -371,6 +394,7 @@ SQLSetConnectOption(HDBC ConnectionHandle,
|
||||
SQLUSMALLINT Option, SQLUINTEGER Value)
|
||||
{
|
||||
mylog("[SQLSetConnectionOption]");
|
||||
CC_clear_error((ConnectionClass *) ConnectionHandle);
|
||||
return PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
|
||||
}
|
||||
|
||||
@ -379,6 +403,7 @@ SQLSetCursorName(HSTMT StatementHandle,
|
||||
SQLCHAR *CursorName, SQLSMALLINT NameLength)
|
||||
{
|
||||
mylog("[SQLSetCursorName]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_SetCursorName(StatementHandle, CursorName, NameLength);
|
||||
}
|
||||
|
||||
@ -390,6 +415,7 @@ SQLSetParam(HSTMT StatementHandle,
|
||||
SQLINTEGER *StrLen_or_Ind)
|
||||
{
|
||||
mylog("[SQLSetParam]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
|
||||
/*
|
||||
* return PGAPI_SetParam(StatementHandle, ParameterNumber, ValueType,
|
||||
@ -404,6 +430,7 @@ SQLSetStmtOption(HSTMT StatementHandle,
|
||||
SQLUSMALLINT Option, SQLUINTEGER Value)
|
||||
{
|
||||
mylog("[SQLSetStmtOption]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_SetStmtOption(StatementHandle, Option, Value);
|
||||
}
|
||||
|
||||
@ -416,6 +443,7 @@ SQLSpecialColumns(HSTMT StatementHandle,
|
||||
SQLUSMALLINT Nullable)
|
||||
{
|
||||
mylog("[SQLSpecialColumns]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_SpecialColumns(StatementHandle, IdentifierType, CatalogName,
|
||||
NameLength1, SchemaName, NameLength2, TableName, NameLength3,
|
||||
Scope, Nullable);
|
||||
@ -429,6 +457,7 @@ SQLStatistics(HSTMT StatementHandle,
|
||||
SQLUSMALLINT Unique, SQLUSMALLINT Reserved)
|
||||
{
|
||||
mylog("[SQLStatistics]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_Statistics(StatementHandle, CatalogName, NameLength1,
|
||||
SchemaName, NameLength2, TableName, NameLength3, Unique,
|
||||
Reserved);
|
||||
@ -442,6 +471,7 @@ SQLTables(HSTMT StatementHandle,
|
||||
SQLCHAR *TableType, SQLSMALLINT NameLength4)
|
||||
{
|
||||
mylog("[SQLTables]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_Tables(StatementHandle, CatalogName, NameLength1,
|
||||
SchemaName, NameLength2, TableName, NameLength3,
|
||||
TableType, NameLength4);
|
||||
@ -466,6 +496,7 @@ SQLColAttributes(
|
||||
SQLINTEGER *pfDesc)
|
||||
{
|
||||
mylog("[SQLColAttributes]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
|
||||
cbDescMax, pcbDesc, pfDesc);
|
||||
}
|
||||
@ -483,6 +514,7 @@ SQLColumnPrivileges(
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
mylog("[SQLColumnPrivileges]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_ColumnPrivileges(hstmt, szCatalogName, cbCatalogName,
|
||||
szSchemaName, cbSchemaName, szTableName, cbTableName,
|
||||
szColumnName, cbColumnName);
|
||||
@ -498,6 +530,7 @@ SQLDescribeParam(
|
||||
SQLSMALLINT *pfNullable)
|
||||
{
|
||||
mylog("[SQLDescribeParam]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_DescribeParam(hstmt, ipar, pfSqlType, pcbParamDef,
|
||||
pibScale, pfNullable);
|
||||
}
|
||||
@ -511,7 +544,8 @@ SQLExtendedFetch(
|
||||
SQLUSMALLINT *rgfRowStatus)
|
||||
{
|
||||
mylog("[SQLExtendedFetch]");
|
||||
return PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus);
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0);
|
||||
}
|
||||
|
||||
RETCODE SQL_API
|
||||
@ -531,6 +565,7 @@ SQLForeignKeys(
|
||||
SQLSMALLINT cbFkTableName)
|
||||
{
|
||||
mylog("[SQLForeignKeys]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_ForeignKeys(hstmt, szPkCatalogName, cbPkCatalogName,
|
||||
szPkSchemaName, cbPkSchemaName, szPkTableName,
|
||||
cbPkTableName, szFkCatalogName, cbFkCatalogName,
|
||||
@ -541,6 +576,7 @@ RETCODE SQL_API
|
||||
SQLMoreResults(HSTMT hstmt)
|
||||
{
|
||||
mylog("[SQLMoreResults]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_MoreResults(hstmt);
|
||||
}
|
||||
|
||||
@ -554,6 +590,7 @@ SQLNativeSql(
|
||||
SQLINTEGER *pcbSqlStr)
|
||||
{
|
||||
mylog("[SQLNativeSql]");
|
||||
CC_clear_error((ConnectionClass *) hdbc);
|
||||
return PGAPI_NativeSql(hdbc, szSqlStrIn, cbSqlStrIn, szSqlStr,
|
||||
cbSqlStrMax, pcbSqlStr);
|
||||
}
|
||||
@ -564,6 +601,7 @@ SQLNumParams(
|
||||
SQLSMALLINT *pcpar)
|
||||
{
|
||||
mylog("[SQLNumParams]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_NumParams(hstmt, pcpar);
|
||||
}
|
||||
|
||||
@ -574,6 +612,7 @@ SQLParamOptions(
|
||||
SQLUINTEGER *pirow)
|
||||
{
|
||||
mylog("[SQLParamOptions]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_ParamOptions(hstmt, crow, pirow);
|
||||
}
|
||||
|
||||
@ -588,6 +627,7 @@ SQLPrimaryKeys(
|
||||
SQLSMALLINT cbTableName)
|
||||
{
|
||||
mylog("[SQLPrimaryKeys]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_PrimaryKeys(hstmt, szCatalogName, cbCatalogName,
|
||||
szSchemaName, cbSchemaName, szTableName, cbTableName);
|
||||
}
|
||||
@ -605,6 +645,7 @@ SQLProcedureColumns(
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
mylog("[SQLProcedureColumns]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_ProcedureColumns(hstmt, szCatalogName, cbCatalogName,
|
||||
szSchemaName, cbSchemaName, szProcName, cbProcName,
|
||||
szColumnName, cbColumnName);
|
||||
@ -621,6 +662,7 @@ SQLProcedures(
|
||||
SQLSMALLINT cbProcName)
|
||||
{
|
||||
mylog("[SQLProcedures]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_Procedures(hstmt, szCatalogName, cbCatalogName,
|
||||
szSchemaName, cbSchemaName, szProcName, cbProcName);
|
||||
}
|
||||
@ -633,6 +675,7 @@ SQLSetPos(
|
||||
SQLUSMALLINT fLock)
|
||||
{
|
||||
mylog("[SQLSetPos]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_SetPos(hstmt, irow, fOption, fLock);
|
||||
}
|
||||
|
||||
@ -647,6 +690,7 @@ SQLTablePrivileges(
|
||||
SQLSMALLINT cbTableName)
|
||||
{
|
||||
mylog("[SQLTablePrivileges]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_TablePrivileges(hstmt, szCatalogName, cbCatalogName,
|
||||
szSchemaName, cbSchemaName, szTableName, cbTableName, 0);
|
||||
}
|
||||
@ -665,6 +709,7 @@ SQLBindParameter(
|
||||
SQLINTEGER *pcbValue)
|
||||
{
|
||||
mylog("[SQLBindParameter]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_BindParameter(hstmt, ipar, fParamType, fCType,
|
||||
fSqlType, cbColDef, ibScale, rgbValue, cbValueMax,
|
||||
pcbValue);
|
||||
|
@ -61,6 +61,7 @@ SQLBindParam(HSTMT StatementHandle,
|
||||
int BufferLength = 512; /* Is it OK ? */
|
||||
|
||||
mylog("[[SQLBindParam]]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_BindParameter(StatementHandle, ParameterNumber, SQL_PARAM_INPUT, ValueType, ParameterType, LengthPrecision, ParameterScale, ParameterValue, BufferLength, StrLen_or_Ind);
|
||||
}
|
||||
|
||||
@ -69,6 +70,7 @@ RETCODE SQL_API
|
||||
SQLCloseCursor(HSTMT StatementHandle)
|
||||
{
|
||||
mylog("[[SQLCloseCursor]]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_FreeStmt(StatementHandle, SQL_CLOSE);
|
||||
}
|
||||
|
||||
@ -80,6 +82,7 @@ SQLColAttribute(HSTMT StatementHandle,
|
||||
SQLSMALLINT *StringLength, PTR NumericAttribute)
|
||||
{
|
||||
mylog("[[SQLColAttribute]]");
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_ColAttributes(StatementHandle, ColumnNumber,
|
||||
FieldIdentifier, CharacterAttribute, BufferLength,
|
||||
StringLength, NumericAttribute);
|
||||
@ -140,6 +143,7 @@ SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
|
||||
case SQL_HANDLE_ENV:
|
||||
return PGAPI_Transact(Handle, SQL_NULL_HDBC, CompletionType);
|
||||
case SQL_HANDLE_DBC:
|
||||
CC_clear_error((ConnectionClass *) Handle);
|
||||
return PGAPI_Transact(SQL_NULL_HENV, Handle, CompletionType);
|
||||
default:
|
||||
break;
|
||||
@ -157,16 +161,18 @@ SQLFetchScroll(HSTMT StatementHandle,
|
||||
RETCODE ret;
|
||||
IRDFields *irdopts = SC_get_IRD(stmt);
|
||||
SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
|
||||
SQLINTEGER *pcRow = irdopts->rowsFetched;
|
||||
SQLINTEGER *pcRow = irdopts->rowsFetched, bkmarkoff = 0;
|
||||
|
||||
mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
|
||||
SC_clear_error(stmt);
|
||||
if (FetchOrientation == SQL_FETCH_BOOKMARK)
|
||||
{
|
||||
if (stmt->options.bookmark_ptr)
|
||||
{
|
||||
FetchOffset += *((Int4 *) stmt->options.bookmark_ptr);
|
||||
mylog("real FetchOffset = %d\n", FetchOffset);
|
||||
}
|
||||
{
|
||||
bkmarkoff = FetchOffset;
|
||||
FetchOffset = *((Int4 *) stmt->options.bookmark_ptr);
|
||||
mylog("bookmark=%u FetchOffset = %d\n", FetchOffset, bkmarkoff);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
@ -176,7 +182,7 @@ mylog("real FetchOffset = %d\n", FetchOffset);
|
||||
}
|
||||
}
|
||||
ret = PGAPI_ExtendedFetch(StatementHandle, FetchOrientation, FetchOffset,
|
||||
pcRow, rowStatusArray);
|
||||
pcRow, rowStatusArray, bkmarkoff);
|
||||
if (ret != SQL_SUCCESS)
|
||||
mylog("%s return = %d\n", func, ret);
|
||||
return ret;
|
||||
@ -288,6 +294,7 @@ SQLGetConnectAttr(HDBC ConnectionHandle,
|
||||
SQLINTEGER BufferLength, SQLINTEGER *StringLength)
|
||||
{
|
||||
mylog("[[SQLGetConnectAttr]] %d\n", Attribute);
|
||||
CC_clear_error((ConnectionClass *) ConnectionHandle);
|
||||
return PGAPI_GetConnectAttr(ConnectionHandle, Attribute,Value,
|
||||
BufferLength, StringLength);
|
||||
}
|
||||
@ -301,6 +308,7 @@ SQLGetStmtAttr(HSTMT StatementHandle,
|
||||
static char *func = "SQLGetStmtAttr";
|
||||
|
||||
mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
|
||||
SC_clear_error((StatementClass *) StatementHandle);
|
||||
return PGAPI_GetStmtAttr(StatementHandle, Attribute, Value,
|
||||
BufferLength, StringLength);
|
||||
}
|
||||
@ -314,6 +322,7 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
|
||||
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
|
||||
|
||||
mylog("[[SQLSetConnectAttr]] %d\n", Attribute);
|
||||
CC_clear_error(conn);
|
||||
return PGAPI_SetConnectAttr(ConnectionHandle, Attribute, Value,
|
||||
StringLength);
|
||||
}
|
||||
@ -396,6 +405,7 @@ SQLSetStmtAttr(HSTMT StatementHandle,
|
||||
StatementClass *stmt = (StatementClass *) StatementHandle;
|
||||
|
||||
mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
|
||||
SC_clear_error(stmt);
|
||||
return PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength);
|
||||
}
|
||||
|
||||
@ -409,6 +419,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
|
||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||
ConnInfo *ci = &(conn->connInfo);
|
||||
|
||||
CC_clear_error(conn);
|
||||
if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS)
|
||||
return SQL_ERROR;
|
||||
memset(pfExists, 0, sizeof(UWORD) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
|
||||
@ -497,12 +508,12 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLENDTRAN); /* 1005 */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLFREEHANDLE); /* 1006 */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETCONNECTATTR); /* 1007 */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD); /* 1008 */
|
||||
if (ci->drivers.lie)
|
||||
{
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD); /* 1008 not implemented yet */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 not implemented yet */
|
||||
}
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 minimal implementation */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGREC); /* 1011 */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETENVATTR); /* 1012 */
|
||||
SQL_FUNC_ESET(pfExists, SQL_API_SQLGETSTMTATTR); /* 1014 */
|
||||
@ -525,72 +536,15 @@ RETCODE SQL_API
|
||||
SQLBulkOperations(HSTMT hstmt, SQLSMALLINT operation)
|
||||
{
|
||||
static char *func = "SQLBulkOperations";
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
#ifndef DRIVER_CURSOR_IMPLEMENT
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||
stmt->errormsg = "driver must be compiled with the DRIVER_CURSOR_IMPLEMENT option";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
#else
|
||||
ARDFields *opts = SC_get_ARD(stmt);
|
||||
RETCODE ret;
|
||||
UInt4 offset, bind_size = opts->bind_size, *bmark;
|
||||
int i, processed;
|
||||
ConnectionClass *conn;
|
||||
BOOL auto_commit_needed = FALSE;
|
||||
|
||||
mylog("[[%s]] operation = %d\n", func, operation);
|
||||
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
|
||||
switch (operation)
|
||||
{
|
||||
case SQL_ADD:
|
||||
ret = PGAPI_SetPos(hstmt, 0, operation, SQL_LOCK_NO_CHANGE);
|
||||
break;
|
||||
default:
|
||||
if (SQL_FETCH_BY_BOOKMARK != operation)
|
||||
{
|
||||
conn = SC_get_conn(stmt);
|
||||
if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
|
||||
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT,
|
||||
SQL_AUTOCOMMIT_OFF);
|
||||
}
|
||||
if (bmark = (UInt4 *) opts->bookmark->buffer, !bmark)
|
||||
{
|
||||
stmt->errormsg = "bookmark isn't specified";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
bmark += (offset >> 4);
|
||||
for (i = 0, processed = 0; i < opts->rowset_size; i++)
|
||||
{
|
||||
if (!opts->row_operation_ptr || SQL_ROW_PROCEED == opts->row_operation_ptr[i])
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case SQL_UPDATE_BY_BOOKMARK:
|
||||
ret = SC_pos_update(stmt, (UWORD) i, *bmark);
|
||||
break;
|
||||
case SQL_DELETE_BY_BOOKMARK:
|
||||
ret = SC_pos_delete(stmt, (UWORD) i, *bmark);
|
||||
break;
|
||||
case SQL_FETCH_BY_BOOKMARK:
|
||||
ret = SC_pos_refresh(stmt, (UWORD) i, *bmark);
|
||||
break;
|
||||
}
|
||||
processed++;
|
||||
if (SQL_ERROR == ret)
|
||||
break;
|
||||
if (bind_size > 0)
|
||||
bmark += (bind_size >> 2);
|
||||
else
|
||||
bmark++;
|
||||
}
|
||||
}
|
||||
if (auto_commit_needed)
|
||||
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
|
||||
if (SC_get_IRD(stmt)->rowsFetched)
|
||||
*SC_get_IRD(stmt)->rowsFetched = processed;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
mylog("[[%s]] Handle=%u %d\n", func, hstmt, operation);
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
return PGAPI_BulkOperations(hstmt, operation);
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ RETCODE SQL_API SQLGetStmtAttrW(SQLHSTMT hstmt,
|
||||
RETCODE ret;
|
||||
|
||||
mylog("[SQLGetStmtAttrW]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue,
|
||||
cbValueMax, pcbValue);
|
||||
return ret;
|
||||
@ -43,6 +44,7 @@ RETCODE SQL_API SQLSetStmtAttrW(SQLHSTMT hstmt,
|
||||
RETCODE ret;
|
||||
|
||||
mylog("[SQLSetStmtAttrW]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue,
|
||||
cbValueMax);
|
||||
return ret;
|
||||
@ -57,6 +59,7 @@ RETCODE SQL_API SQLGetConnectAttrW(HDBC hdbc,
|
||||
RETCODE ret;
|
||||
|
||||
mylog("[SQLGetConnectAttrW]");
|
||||
CC_clear_error((ConnectionClass *) hdbc);
|
||||
ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue,
|
||||
cbValueMax, pcbValue);
|
||||
return ret;
|
||||
@ -70,6 +73,7 @@ RETCODE SQL_API SQLSetConnectAttrW(HDBC hdbc,
|
||||
RETCODE ret;
|
||||
|
||||
mylog("[SQLSetConnectAttrW]");
|
||||
CC_clear_error((ConnectionClass *) hdbc);
|
||||
ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue,
|
||||
cbValue);
|
||||
return ret;
|
||||
@ -229,6 +233,7 @@ RETCODE SQL_API SQLColAttributeW(
|
||||
char *rgbD = NULL;
|
||||
|
||||
mylog("[SQLColAttributeW]");
|
||||
SC_clear_error((StatementClass *) hstmt);
|
||||
switch (fDescType)
|
||||
{
|
||||
case SQL_DESC_BASE_COLUMN_NAME:
|
||||
|
@ -95,9 +95,13 @@ set_statement_option(ConnectionClass *conn,
|
||||
;
|
||||
else if (SQL_CURSOR_STATIC == vParam)
|
||||
setval = vParam;
|
||||
/** else if (SQL_CURSOR_KEYSET_DRIVEN == vParam && ci->updatable)
|
||||
setval = vParam; **/
|
||||
|
||||
else if (SQL_CURSOR_KEYSET_DRIVEN == vParam)
|
||||
{
|
||||
if (ci->updatable_cursors)
|
||||
setval = vParam;
|
||||
else
|
||||
setval = SQL_CURSOR_STATIC; /* at least scrollable */
|
||||
}
|
||||
if (conn)
|
||||
conn->stmtOptions.cursor_type = setval;
|
||||
else if (stmt)
|
||||
@ -372,6 +376,60 @@ PGAPI_SetConnectOption(
|
||||
break;
|
||||
|
||||
case SQL_TXN_ISOLATION: /* ignored */
|
||||
retval = SQL_SUCCESS;
|
||||
if (CC_is_in_trans(conn))
|
||||
{
|
||||
conn->errormsg = "Cannot switch isolation level while a transaction is in progress";
|
||||
conn->errornumber = CONN_TRANSACT_IN_PROGRES;
|
||||
CC_log_error(func, "", conn);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
if (conn->isolation == vParam)
|
||||
break;
|
||||
switch (vParam)
|
||||
{
|
||||
case SQL_TXN_SERIALIZABLE:
|
||||
if (PG_VERSION_GE(conn, 6.5) &&
|
||||
PG_VERSION_LE(conn, 7.0))
|
||||
retval = SQL_ERROR;
|
||||
break;
|
||||
case SQL_TXN_READ_COMMITTED:
|
||||
if (PG_VERSION_LT(conn, 6.5))
|
||||
retval = SQL_ERROR;
|
||||
break;
|
||||
default:
|
||||
retval = SQL_ERROR;
|
||||
}
|
||||
if (SQL_ERROR == retval)
|
||||
{
|
||||
conn->errornumber = CONN_INVALID_ARGUMENT_NO;
|
||||
conn->errormsg = "Illegal parameter value for SQL_TXN_ISOLATION";
|
||||
CC_log_error(func, "", conn);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *query;
|
||||
QResultClass *res;
|
||||
|
||||
if (vParam == SQL_TXN_SERIALIZABLE)
|
||||
query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
|
||||
else
|
||||
query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
|
||||
res = CC_send_query(conn, query, NULL, 0);
|
||||
if (!res || !QR_command_maybe_successful(res))
|
||||
retval = SQL_ERROR;
|
||||
else
|
||||
conn->isolation = vParam;
|
||||
if (res)
|
||||
QR_Destructor(res);
|
||||
if (SQL_ERROR == retval)
|
||||
{
|
||||
conn->errornumber = STMT_EXEC_ERROR;
|
||||
conn->errormsg = "ISOLATION change request to the server error";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* These options should be handled by driver manager */
|
||||
@ -476,8 +534,8 @@ PGAPI_GetConnectOption(
|
||||
*((UDWORD *) pvParam) = (UDWORD) NULL;
|
||||
break;
|
||||
|
||||
case SQL_TXN_ISOLATION: /* NOT SUPPORTED */
|
||||
*((UDWORD *) pvParam) = SQL_TXN_READ_COMMITTED;
|
||||
case SQL_TXN_ISOLATION:
|
||||
*((UDWORD *) pvParam) = conn->isolation;
|
||||
break;
|
||||
|
||||
/* These options should be handled by driver manager */
|
||||
@ -567,7 +625,7 @@ PGAPI_GetStmtOption(
|
||||
{
|
||||
/* make sure we're positioned on a valid row */
|
||||
if ((stmt->currTuple < 0) ||
|
||||
(stmt->currTuple >= QR_get_num_tuples(res)))
|
||||
(stmt->currTuple >= QR_get_num_backend_tuples(res)))
|
||||
{
|
||||
stmt->errormsg = "Not positioned on a valid row.";
|
||||
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
|
||||
|
@ -50,6 +50,29 @@ char *getNextToken(char *s, char *token, int smax, char *delim, char *quote,
|
||||
void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
|
||||
char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
|
||||
|
||||
Int4 FI_precision(const FIELD_INFO *fi)
|
||||
{
|
||||
if (!fi) return -1;
|
||||
switch (fi->type)
|
||||
{
|
||||
case PG_TYPE_NUMERIC:
|
||||
return fi->column_size;
|
||||
case PG_TYPE_DATETIME:
|
||||
case PG_TYPE_TIMESTAMP_NO_TMZONE:
|
||||
return fi->decimal_digits;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Int4 FI_scale(const FIELD_INFO *fi)
|
||||
{
|
||||
if (!fi) return -1;
|
||||
switch (fi->type)
|
||||
{
|
||||
case PG_TYPE_NUMERIC:
|
||||
return fi->decimal_digits;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
getNextToken(
|
||||
@ -265,7 +288,7 @@ searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
|
||||
cmp;
|
||||
char *col;
|
||||
|
||||
for (k = 0; k < QR_get_num_tuples(col_info->result); k++)
|
||||
for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
|
||||
{
|
||||
col = QR_get_value_manual(col_info->result, k, 3);
|
||||
if (fi->dquote)
|
||||
@ -291,7 +314,7 @@ char
|
||||
parse_statement(StatementClass *stmt)
|
||||
{
|
||||
static char *func = "parse_statement";
|
||||
char token[256];
|
||||
char token[256], stoken[256];
|
||||
char delim,
|
||||
quote,
|
||||
dquote,
|
||||
@ -315,7 +338,7 @@ parse_statement(StatementClass *stmt)
|
||||
i,
|
||||
k = 0,
|
||||
n,
|
||||
blevel = 0;
|
||||
blevel = 0, old_blevel, subqlevel = 0;
|
||||
FIELD_INFO **fi;
|
||||
TABLE_INFO **ti;
|
||||
char parse;
|
||||
@ -347,7 +370,10 @@ parse_statement(StatementClass *stmt)
|
||||
|
||||
mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
|
||||
|
||||
if (in_select && unquoted && blevel == 0)
|
||||
old_blevel = blevel;
|
||||
if (unquoted && blevel == 0)
|
||||
{
|
||||
if (in_select)
|
||||
{
|
||||
if (!stricmp(token, "distinct"))
|
||||
{
|
||||
@ -357,7 +383,7 @@ parse_statement(StatementClass *stmt)
|
||||
mylog("DISTINCT\n");
|
||||
continue;
|
||||
}
|
||||
if (!stricmp(token, "into"))
|
||||
else if (!stricmp(token, "into"))
|
||||
{
|
||||
in_select = FALSE;
|
||||
mylog("INTO\n");
|
||||
@ -365,7 +391,7 @@ parse_statement(StatementClass *stmt)
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
return FALSE;
|
||||
}
|
||||
if (!stricmp(token, "from"))
|
||||
else if (!stricmp(token, "from"))
|
||||
{
|
||||
in_select = FALSE;
|
||||
in_from = TRUE;
|
||||
@ -380,9 +406,7 @@ parse_statement(StatementClass *stmt)
|
||||
continue;
|
||||
}
|
||||
} /* in_select && unquoted && blevel == 0 */
|
||||
if (unquoted && blevel == 0)
|
||||
{
|
||||
if ((!stricmp(token, "where") ||
|
||||
else if ((!stricmp(token, "where") ||
|
||||
!stricmp(token, "union") ||
|
||||
!stricmp(token, "intersect") ||
|
||||
!stricmp(token, "except") ||
|
||||
@ -390,7 +414,6 @@ parse_statement(StatementClass *stmt)
|
||||
!stricmp(token, "group") ||
|
||||
!stricmp(token, "having")))
|
||||
{
|
||||
in_select = FALSE;
|
||||
in_from = FALSE;
|
||||
in_where = TRUE;
|
||||
|
||||
@ -406,24 +429,61 @@ parse_statement(StatementClass *stmt)
|
||||
continue;
|
||||
}
|
||||
} /* unquoted && blevel == 0 */
|
||||
if (in_select && (in_expr || in_func))
|
||||
{
|
||||
/* just eat the expression */
|
||||
mylog("in_expr=%d or func=%d\n", in_expr, in_func);
|
||||
|
||||
/* check the change of blevel etc */
|
||||
if (unquoted)
|
||||
{
|
||||
if (token[0] == '(')
|
||||
if (!stricmp(token, "select"))
|
||||
{
|
||||
stoken[0] = '\0';
|
||||
if (0 == blevel)
|
||||
{
|
||||
in_select = TRUE;
|
||||
mylog("SELECT\n");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
mylog("SUBSELECT\n");
|
||||
if (0 == subqlevel)
|
||||
subqlevel = blevel;
|
||||
}
|
||||
}
|
||||
else if (token[0] == '(')
|
||||
{
|
||||
blevel++;
|
||||
mylog("blevel++ = %d\n", blevel);
|
||||
/* aggregate function ? */
|
||||
if (stoken[0] && updatable && 0 == subqlevel)
|
||||
{
|
||||
if (stricmp(stoken, "count") == 0 ||
|
||||
stricmp(stoken, "sum") == 0 ||
|
||||
stricmp(stoken, "avg") == 0 ||
|
||||
stricmp(stoken, "max") == 0 ||
|
||||
stricmp(stoken, "min") == 0 ||
|
||||
stricmp(stoken, "variance") == 0 ||
|
||||
stricmp(stoken, "stddev") == 0)
|
||||
updatable = FALSE;
|
||||
}
|
||||
}
|
||||
else if (token[0] == ')')
|
||||
{
|
||||
blevel--;
|
||||
mylog("blevel-- = %d\n", blevel);
|
||||
if (blevel < subqlevel)
|
||||
subqlevel = 0;
|
||||
}
|
||||
if (blevel >= old_blevel && ',' != delim)
|
||||
strcpy(stoken, token);
|
||||
else
|
||||
stoken[0] = '\0';
|
||||
}
|
||||
if (in_select)
|
||||
{
|
||||
if (in_expr || in_func)
|
||||
{
|
||||
/* just eat the expression */
|
||||
mylog("in_expr=%d or func=%d\n", in_expr, in_func);
|
||||
|
||||
if (blevel == 0)
|
||||
{
|
||||
if (delim == ',')
|
||||
@ -443,17 +503,8 @@ parse_statement(StatementClass *stmt)
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} /* in_select && (in_expr || in_func) */
|
||||
} /* (in_expr || in_func) && in_select */
|
||||
|
||||
if (unquoted && !stricmp(token, "select"))
|
||||
{
|
||||
in_select = TRUE;
|
||||
|
||||
mylog("SELECT\n");
|
||||
continue;
|
||||
}
|
||||
if (in_select)
|
||||
{
|
||||
if (in_distinct)
|
||||
{
|
||||
mylog("in distinct\n");
|
||||
@ -515,12 +566,11 @@ parse_statement(StatementClass *stmt)
|
||||
mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
|
||||
fi[irdflds->nfields]->numeric = TRUE;
|
||||
}
|
||||
else if (token[0] == '(')
|
||||
else if (0 == old_blevel && blevel > 0)
|
||||
{ /* expression */
|
||||
mylog("got EXPRESSION\n");
|
||||
fi[irdflds->nfields++]->expr = TRUE;
|
||||
in_expr = TRUE;
|
||||
blevel = 1;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@ -579,11 +629,10 @@ parse_statement(StatementClass *stmt)
|
||||
}
|
||||
|
||||
/* Function */
|
||||
if (token[0] == '(')
|
||||
if (0 == old_blevel && blevel > 0)
|
||||
{
|
||||
in_dot = FALSE;
|
||||
in_func = TRUE;
|
||||
blevel = 1;
|
||||
fi[irdflds->nfields - 1]->func = TRUE;
|
||||
|
||||
/*
|
||||
@ -654,6 +703,7 @@ parse_statement(StatementClass *stmt)
|
||||
|
||||
ti[stmt->ntab]->schema[0] = '\0';
|
||||
ti[stmt->ntab]->alias[0] = '\0';
|
||||
ti[stmt->ntab]->updatable = 1;
|
||||
|
||||
strcpy(ti[stmt->ntab]->name, token);
|
||||
if (!dquote)
|
||||
@ -845,6 +895,37 @@ parse_statement(StatementClass *stmt)
|
||||
col_stmt = (StatementClass *) hcol_stmt;
|
||||
col_stmt->internal = TRUE;
|
||||
|
||||
if (!ti[i]->schema[0] && conn->schema_support)
|
||||
{
|
||||
QResultClass *res;
|
||||
BOOL tblFound = FALSE;
|
||||
|
||||
/* Unfortunately CURRENT_SCHEMA doesn't exist
|
||||
* in PostgreSQL and we have to check as follows.
|
||||
*/
|
||||
sprintf(token, "select nspname from pg_namespace n, pg_class c"
|
||||
" where c.relnamespace=n.oid and c.oid='%s'::regclass", ti[i]->name);
|
||||
res = CC_send_query(conn, token, NULL, CLEAR_RESULT_ON_ABORT);
|
||||
if (res)
|
||||
{
|
||||
if (QR_get_num_total_tuples(res) == 1)
|
||||
{
|
||||
tblFound = TRUE;
|
||||
strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
|
||||
}
|
||||
QR_Destructor(res);
|
||||
}
|
||||
else
|
||||
CC_abort(conn);
|
||||
if (!tblFound)
|
||||
{
|
||||
stmt->parse_status = STMT_PARSE_FATAL;
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
stmt->errormsg = "Table not found";
|
||||
stmt->updatable = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
|
||||
SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
|
||||
|
||||
@ -907,6 +988,8 @@ parse_statement(StatementClass *stmt)
|
||||
/*
|
||||
* Now resolve the fields to point to column info
|
||||
*/
|
||||
if (updatable && 1 == stmt->ntab)
|
||||
updatable = stmt->ti[0]->updatable;
|
||||
for (i = 0; i < (int) irdflds->nfields;)
|
||||
{
|
||||
fi[i]->updatable = updatable;
|
||||
@ -934,14 +1017,14 @@ parse_statement(StatementClass *stmt)
|
||||
|
||||
if (fi[i]->ti) /* The star represents only the qualified
|
||||
* table */
|
||||
total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result);
|
||||
total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
|
||||
|
||||
else
|
||||
{ /* The star represents all tables */
|
||||
|
||||
/* Calculate the total number of columns after expansion */
|
||||
for (k = 0; k < stmt->ntab; k++)
|
||||
total_cols += QR_get_num_tuples(ti[k]->col_info->result);
|
||||
total_cols += QR_get_num_backend_tuples(ti[k]->col_info->result);
|
||||
}
|
||||
increased_cols = total_cols - 1;
|
||||
|
||||
@ -988,7 +1071,7 @@ parse_statement(StatementClass *stmt)
|
||||
{
|
||||
TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
|
||||
|
||||
cols = QR_get_num_tuples(the_ti->col_info->result);
|
||||
cols = QR_get_num_backend_tuples(the_ti->col_info->result);
|
||||
|
||||
for (n = 0; n < cols; n++)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "connection.h"
|
||||
#include "statement.h"
|
||||
#include "descriptor.h"
|
||||
#include "qresult.h"
|
||||
#include "pgapifunc.h"
|
||||
|
||||
static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType);
|
||||
@ -69,13 +70,22 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Minimal implementation.
|
||||
*
|
||||
*/
|
||||
RETCODE SQL_API
|
||||
PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
|
||||
SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier,
|
||||
PTR DiagInfoPtr, SQLSMALLINT BufferLength,
|
||||
SQLSMALLINT *StringLengthPtr)
|
||||
{
|
||||
RETCODE ret = SQL_ERROR;
|
||||
RETCODE ret = SQL_ERROR, rtn;
|
||||
ConnectionClass *conn;
|
||||
SQLHANDLE stmtHandle;
|
||||
StatementClass *stmt;
|
||||
SDWORD rc;
|
||||
SWORD pcbErrm;
|
||||
static const char *func = "PGAPI_GetDiagField";
|
||||
|
||||
mylog("%s entering rec=%d", func, RecNumber);
|
||||
@ -87,43 +97,243 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
|
||||
case SQL_DIAG_CLASS_ORIGIN:
|
||||
case SQL_DIAG_SUBCLASS_ORIGIN:
|
||||
case SQL_DIAG_CONNECTION_NAME:
|
||||
case SQL_DIAG_MESSAGE_TEXT:
|
||||
case SQL_DIAG_NATIVE:
|
||||
case SQL_DIAG_NUMBER:
|
||||
case SQL_DIAG_RETURNCODE:
|
||||
case SQL_DIAG_SERVER_NAME:
|
||||
strcpy((char *) DiagInfoPtr, "");
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = 0;
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_MESSAGE_TEXT:
|
||||
ret = PGAPI_EnvError(Handle, RecNumber,
|
||||
NULL, NULL, DiagInfoPtr,
|
||||
BufferLength, StringLengthPtr, 0);
|
||||
break;
|
||||
case SQL_DIAG_NATIVE:
|
||||
ret = PGAPI_EnvError(Handle, RecNumber,
|
||||
NULL, DiagInfoPtr, NULL,
|
||||
0, NULL, 0);
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
if (SQL_SUCCESS_WITH_INFO == ret)
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_NUMBER:
|
||||
ret = PGAPI_EnvError(Handle, RecNumber,
|
||||
NULL, NULL, NULL,
|
||||
0, NULL, 0);
|
||||
if (SQL_SUCCESS == ret ||
|
||||
SQL_SUCCESS_WITH_INFO == ret)
|
||||
{
|
||||
*((SQLINTEGER *) DiagInfoPtr) = 1;
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
ret = SQL_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case SQL_DIAG_SQLSTATE:
|
||||
ret = PGAPI_EnvError(Handle, RecNumber,
|
||||
DiagInfoPtr, NULL, NULL,
|
||||
0, NULL, 0);
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = 5;
|
||||
if (SQL_SUCCESS_WITH_INFO == ret)
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_RETURNCODE: /* driver manager returns */
|
||||
break;
|
||||
case SQL_DIAG_CURSOR_ROW_COUNT:
|
||||
case SQL_DIAG_ROW_COUNT:
|
||||
case SQL_DIAG_DYNAMIC_FUNCTION:
|
||||
case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
|
||||
/* options for statement type only */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SQL_HANDLE_DBC:
|
||||
conn = (ConnectionClass *) Handle;
|
||||
switch (DiagIdentifier)
|
||||
{
|
||||
case SQL_DIAG_CLASS_ORIGIN:
|
||||
case SQL_DIAG_SUBCLASS_ORIGIN:
|
||||
case SQL_DIAG_CONNECTION_NAME:
|
||||
case SQL_DIAG_MESSAGE_TEXT:
|
||||
case SQL_DIAG_NATIVE:
|
||||
case SQL_DIAG_NUMBER:
|
||||
case SQL_DIAG_RETURNCODE:
|
||||
strcpy((char *) DiagInfoPtr, "");
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = 0;
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_SERVER_NAME:
|
||||
strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = strlen(CC_get_DSN(conn));
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_MESSAGE_TEXT:
|
||||
ret = PGAPI_ConnectError(Handle, RecNumber,
|
||||
NULL, NULL, DiagInfoPtr,
|
||||
BufferLength, StringLengthPtr, 0);
|
||||
break;
|
||||
case SQL_DIAG_NATIVE:
|
||||
ret = PGAPI_ConnectError(Handle, RecNumber,
|
||||
NULL, DiagInfoPtr, NULL,
|
||||
0, NULL, 0);
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
if (SQL_SUCCESS_WITH_INFO == ret)
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_NUMBER:
|
||||
ret = PGAPI_ConnectError(Handle, RecNumber,
|
||||
NULL, NULL, NULL,
|
||||
0, NULL, 0);
|
||||
if (SQL_SUCCESS == ret ||
|
||||
SQL_SUCCESS_WITH_INFO == ret)
|
||||
{
|
||||
*((SQLINTEGER *) DiagInfoPtr) = 1;
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
ret = SQL_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case SQL_DIAG_SQLSTATE:
|
||||
ret = PGAPI_ConnectError(Handle, RecNumber,
|
||||
DiagInfoPtr, NULL, NULL,
|
||||
0, NULL, 0);
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = 5;
|
||||
if (SQL_SUCCESS_WITH_INFO == ret)
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_RETURNCODE: /* driver manager returns */
|
||||
break;
|
||||
case SQL_DIAG_CURSOR_ROW_COUNT:
|
||||
case SQL_DIAG_ROW_COUNT:
|
||||
case SQL_DIAG_DYNAMIC_FUNCTION:
|
||||
case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
|
||||
/* options for statement type only */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SQL_HANDLE_STMT:
|
||||
conn = (ConnectionClass *) SC_get_conn(((StatementClass *) Handle));
|
||||
switch (DiagIdentifier)
|
||||
{
|
||||
case SQL_DIAG_CLASS_ORIGIN:
|
||||
case SQL_DIAG_SUBCLASS_ORIGIN:
|
||||
case SQL_DIAG_CONNECTION_NAME:
|
||||
strcpy((char *) DiagInfoPtr, "");
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = 0;
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_SERVER_NAME:
|
||||
strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = strlen(CC_get_DSN(conn));
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_MESSAGE_TEXT:
|
||||
ret = PGAPI_StmtError(Handle, RecNumber,
|
||||
NULL, NULL, DiagInfoPtr,
|
||||
BufferLength, StringLengthPtr, 0);
|
||||
break;
|
||||
case SQL_DIAG_NATIVE:
|
||||
ret = PGAPI_StmtError(Handle, RecNumber,
|
||||
NULL, DiagInfoPtr, NULL,
|
||||
0, NULL, 0);
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
if (SQL_SUCCESS_WITH_INFO == ret)
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_NUMBER:
|
||||
*((SQLINTEGER *) DiagInfoPtr) = 0;
|
||||
ret = SQL_NO_DATA_FOUND;
|
||||
stmt = (StatementClass *) Handle;
|
||||
do
|
||||
{
|
||||
rtn = PGAPI_StmtError(Handle, RecNumber,
|
||||
NULL, NULL, NULL,
|
||||
0, &pcbErrm, 0);
|
||||
if (SQL_SUCCESS == rtn ||
|
||||
SQL_SUCCESS_WITH_INFO == rtn)
|
||||
{
|
||||
*((SQLINTEGER *) DiagInfoPtr)++;
|
||||
ret = SQL_SUCCESS;
|
||||
}
|
||||
} while (pcbErrm >= stmt->error_recsize);
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
break;
|
||||
case SQL_DIAG_SQLSTATE:
|
||||
ret = PGAPI_StmtError(Handle, RecNumber,
|
||||
DiagInfoPtr, NULL, NULL,
|
||||
0, NULL, 0);
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = 5;
|
||||
if (SQL_SUCCESS_WITH_INFO == ret)
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_CURSOR_ROW_COUNT:
|
||||
stmt = (StatementClass *) Handle;
|
||||
rc = -1;
|
||||
if (stmt->status == STMT_FINISHED)
|
||||
{
|
||||
QResultClass *res = SC_get_Curres(stmt);
|
||||
|
||||
if (res && QR_NumResultCols(res) > 0 && !SC_is_fetchcursor(stmt))
|
||||
rc = QR_get_num_total_tuples(res) - res->dl_count;
|
||||
}
|
||||
*((SQLINTEGER *) DiagInfoPtr) = rc;
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_ROW_COUNT:
|
||||
stmt = (StatementClass *) Handle;
|
||||
*((SQLINTEGER *) DiagInfoPtr) = stmt->diag_row_count;
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = sizeof(SQLINTEGER);
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_RETURNCODE: /* driver manager returns */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SQL_HANDLE_DESC:
|
||||
stmtHandle = statementHandleFromDescHandle(Handle, NULL);
|
||||
conn = (ConnectionClass *) SC_get_conn(((StatementClass *) stmtHandle));
|
||||
switch (DiagIdentifier)
|
||||
{
|
||||
case SQL_DIAG_CLASS_ORIGIN:
|
||||
case SQL_DIAG_SUBCLASS_ORIGIN:
|
||||
case SQL_DIAG_CONNECTION_NAME:
|
||||
strcpy((char *) DiagInfoPtr, "");
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = 0;
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_SERVER_NAME:
|
||||
strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
|
||||
if (StringLengthPtr)
|
||||
*StringLengthPtr = strlen(CC_get_DSN(conn));
|
||||
ret = SQL_SUCCESS;
|
||||
break;
|
||||
case SQL_DIAG_MESSAGE_TEXT:
|
||||
case SQL_DIAG_NATIVE:
|
||||
case SQL_DIAG_NUMBER:
|
||||
case SQL_DIAG_RETURNCODE:
|
||||
case SQL_DIAG_SERVER_NAME:
|
||||
break;
|
||||
case SQL_DIAG_SQLSTATE:
|
||||
ret = PGAPI_GetDiagField(SQL_HANDLE_STMT,
|
||||
stmtHandle, RecNumber,
|
||||
DiagIdentifier, DiagInfoPtr,
|
||||
BufferLength, StringLengthPtr);
|
||||
break;
|
||||
case SQL_DIAG_RETURNCODE: /* driver manager returns */
|
||||
break;
|
||||
case SQL_DIAG_CURSOR_ROW_COUNT:
|
||||
case SQL_DIAG_ROW_COUNT:
|
||||
case SQL_DIAG_DYNAMIC_FUNCTION:
|
||||
case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
|
||||
/* options for statement type only */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -155,12 +365,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle,
|
||||
*((SQLUINTEGER *) Value) = SQL_FALSE;
|
||||
break;
|
||||
case SQL_ATTR_CONNECTION_DEAD:
|
||||
if (CC_is_in_trans(conn))
|
||||
*((SQLUINTEGER *) Value) = SQL_CD_FALSE;
|
||||
else if (conn->num_stmts > 0)
|
||||
*((SQLUINTEGER *) Value) = SQL_CD_FALSE;
|
||||
else
|
||||
*((SQLUINTEGER *) Value) = SQL_CD_FALSE;
|
||||
*((SQLUINTEGER *) Value) = (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN);
|
||||
break;
|
||||
case SQL_ATTR_CONNECTION_TIMEOUT:
|
||||
*((SQLUINTEGER *) Value) = 0;
|
||||
@ -348,12 +553,24 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
opts->bindings[RecNumber - 1].buflen = (Int4) Value;
|
||||
}
|
||||
break;
|
||||
case SQL_DESC_PRECISION:
|
||||
if (RecNumber)
|
||||
{
|
||||
column_bindings_set(opts, RecNumber, TRUE);
|
||||
opts->bindings[RecNumber - 1].precision = (Int2) Value;
|
||||
}
|
||||
break;
|
||||
case SQL_DESC_SCALE:
|
||||
if (RecNumber)
|
||||
{
|
||||
column_bindings_set(opts, RecNumber, TRUE);
|
||||
opts->bindings[RecNumber - 1].scale = (Int4) Value;
|
||||
}
|
||||
break;
|
||||
case SQL_DESC_ALLOC_TYPE: /* read-only */
|
||||
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
|
||||
case SQL_DESC_LENGTH:
|
||||
case SQL_DESC_NUM_PREC_RADIX:
|
||||
case SQL_DESC_PRECISION:
|
||||
case SQL_DESC_SCALE:
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
|
||||
}
|
||||
@ -460,12 +677,18 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
case SQL_DESC_COUNT:
|
||||
parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
|
||||
break;
|
||||
case SQL_DESC_PRECISION:
|
||||
parameter_bindings_set(opts, RecNumber, TRUE);
|
||||
opts->parameters[RecNumber - 1].precision = (Int2) Value;
|
||||
break;
|
||||
case SQL_DESC_SCALE:
|
||||
parameter_bindings_set(opts, RecNumber, TRUE);
|
||||
opts->parameters[RecNumber - 1].scale = (Int2) Value;
|
||||
break;
|
||||
case SQL_DESC_ALLOC_TYPE: /* read-only */
|
||||
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
|
||||
case SQL_DESC_LENGTH:
|
||||
case SQL_DESC_NUM_PREC_RADIX:
|
||||
case SQL_DESC_PRECISION:
|
||||
case SQL_DESC_SCALE:
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
|
||||
}
|
||||
@ -710,11 +933,23 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
case SQL_DESC_ALLOC_TYPE: /* read-only */
|
||||
ival = SQL_DESC_ALLOC_AUTO;
|
||||
break;
|
||||
case SQL_DESC_PRECISION:
|
||||
if (RecNumber)
|
||||
{
|
||||
ival = opts->bindings[RecNumber - 1].precision;
|
||||
}
|
||||
break;
|
||||
case SQL_DESC_SCALE:
|
||||
if (RecNumber)
|
||||
{
|
||||
ival = opts->bindings[RecNumber - 1].scale;
|
||||
}
|
||||
break;
|
||||
case SQL_DESC_NUM_PREC_RADIX:
|
||||
ival = 10;
|
||||
break;
|
||||
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
|
||||
case SQL_DESC_LENGTH:
|
||||
case SQL_DESC_NUM_PREC_RADIX:
|
||||
case SQL_DESC_PRECISION:
|
||||
case SQL_DESC_SCALE:
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
|
||||
}
|
||||
@ -818,11 +1053,17 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
case SQL_DESC_ALLOC_TYPE: /* read-only */
|
||||
ival = SQL_DESC_ALLOC_AUTO;
|
||||
break;
|
||||
case SQL_DESC_NUM_PREC_RADIX:
|
||||
ival = 10;
|
||||
break;
|
||||
case SQL_DESC_PRECISION:
|
||||
ival = opts->parameters[RecNumber - 1].precision;
|
||||
break;
|
||||
case SQL_DESC_SCALE:
|
||||
ival = opts->parameters[RecNumber - 1].scale;
|
||||
break;
|
||||
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
|
||||
case SQL_DESC_LENGTH:
|
||||
case SQL_DESC_NUM_PREC_RADIX:
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_DESCRIPTOR_IDENTIFIER;
|
||||
}
|
||||
@ -1339,3 +1580,77 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle,
|
||||
}
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
RETCODE SQL_API
|
||||
PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operation)
|
||||
{
|
||||
static char *func = "PGAPI_BulkOperations";
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
ARDFields *opts = SC_get_ARD(stmt);
|
||||
RETCODE ret;
|
||||
UInt4 offset, bind_size = opts->bind_size, *bmark = NULL;
|
||||
int i, processed;
|
||||
ConnectionClass *conn;
|
||||
BOOL auto_commit_needed = FALSE;
|
||||
QResultClass *res;
|
||||
|
||||
mylog("%s operation = %d\n", func, operation);
|
||||
SC_clear_error(stmt);
|
||||
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
|
||||
|
||||
if (SQL_FETCH_BY_BOOKMARK != operation)
|
||||
{
|
||||
conn = SC_get_conn(stmt);
|
||||
if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
|
||||
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
|
||||
}
|
||||
if (SQL_ADD != operation)
|
||||
{
|
||||
if (bmark = (UInt4 *) opts->bookmark->buffer, !bmark)
|
||||
{
|
||||
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
|
||||
stmt->errormsg = "bookmark isn't specified";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
bmark += (offset >> 4);
|
||||
}
|
||||
for (i = 0, processed = 0; i < opts->rowset_size; i++)
|
||||
{
|
||||
/* Note opts->row_operation_ptr is ignored */
|
||||
switch (operation)
|
||||
{
|
||||
case SQL_ADD:
|
||||
ret = SC_pos_add(stmt, (UWORD) i);
|
||||
break;
|
||||
case SQL_UPDATE_BY_BOOKMARK:
|
||||
ret = SC_pos_update(stmt, (UWORD) i, *bmark);
|
||||
break;
|
||||
case SQL_DELETE_BY_BOOKMARK:
|
||||
ret = SC_pos_delete(stmt, (UWORD) i, *bmark);
|
||||
break;
|
||||
case SQL_FETCH_BY_BOOKMARK:
|
||||
ret = SC_pos_refresh(stmt, (UWORD) i, *bmark);
|
||||
break;
|
||||
}
|
||||
processed++;
|
||||
if (SQL_ERROR == ret)
|
||||
break;
|
||||
if (SQL_ADD != operation)
|
||||
{
|
||||
if (bind_size > 0)
|
||||
bmark += (bind_size >> 2);
|
||||
else
|
||||
bmark++;
|
||||
}
|
||||
}
|
||||
if (auto_commit_needed)
|
||||
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
|
||||
if (SC_get_IRD(stmt)->rowsFetched)
|
||||
*(SC_get_IRD(stmt)->rowsFetched) = processed;
|
||||
|
||||
if (res = SC_get_Curres(stmt), res)
|
||||
res->recent_processed_row_count = stmt->diag_row_count = processed;
|
||||
return ret;
|
||||
}
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
|
@ -172,7 +172,8 @@ RETCODE SQL_API PGAPI_ExtendedFetch(
|
||||
SQLUSMALLINT fFetchType,
|
||||
SQLINTEGER irow,
|
||||
SQLUINTEGER *pcrow,
|
||||
SQLUSMALLINT *rgfRowStatus);
|
||||
SQLUSMALLINT *rgfRowStatus,
|
||||
SQLINTEGER FetchOffset);
|
||||
RETCODE SQL_API PGAPI_ForeignKeys(
|
||||
HSTMT hstmt,
|
||||
SQLCHAR *szPkCatalogName,
|
||||
@ -281,6 +282,8 @@ RETCODE SQL_API PGAPI_SetConnectAttr(HDBC ConnectionHandle,
|
||||
RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle,
|
||||
SQLINTEGER Attribute, PTR Value,
|
||||
SQLINTEGER StringLength);
|
||||
RETCODE SQL_API PGAPI_BulkOperations(HSTMT StatementHandle,
|
||||
SQLSMALLINT operation);
|
||||
RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle,
|
||||
SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
|
||||
PTR Value, SQLINTEGER BufferLength);
|
||||
|
@ -101,7 +101,8 @@ Int2 sqlTypes[] = {
|
||||
};
|
||||
|
||||
#if (ODBCVER >= 0x0300) && defined(OBDCINT64)
|
||||
#define ALLOWED_C_BIGINT SQL_C_SBIGINT
|
||||
/* #define ALLOWED_C_BIGINT SQL_C_SBIGINT */
|
||||
#define ALLOWED_C_BIGINT SQL_C_CHAR /* Delphi should be either ? */
|
||||
#else
|
||||
#define ALLOWED_C_BIGINT SQL_C_CHAR
|
||||
#endif
|
||||
@ -286,11 +287,13 @@ pgtype_to_concise_type(StatementClass *stmt, Int4 type)
|
||||
|
||||
/* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
|
||||
case PG_TYPE_INT8:
|
||||
if (conn->ms_jet)
|
||||
return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */
|
||||
#if (ODBCVER >= 0x0300)
|
||||
if (!conn->ms_jet)
|
||||
return SQL_BIGINT;
|
||||
#endif /* ODBCVER */
|
||||
#else
|
||||
return SQL_VARCHAR;
|
||||
#endif /* ODBCVER */
|
||||
|
||||
case PG_TYPE_NUMERIC:
|
||||
return SQL_NUMERIC;
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* Comments: See "notice.txt" for copyright and license information.
|
||||
*
|
||||
* $Id: psqlodbc.h,v 1.65 2002/04/15 02:46:00 inoue Exp $
|
||||
* $Id: psqlodbc.h,v 1.66 2002/05/22 05:51:03 inoue Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
|
||||
#include <stdio.h> /* for FILE* pointers: see GLOBAL_VALUES */
|
||||
|
||||
#include "version.h"
|
||||
|
||||
/* Must come before sql.h */
|
||||
#ifndef ODBCVER
|
||||
#define ODBCVER 0x0250
|
||||
@ -87,8 +89,6 @@ typedef UInt4 Oid;
|
||||
#define DBMS_NAME "PostgreSQL"
|
||||
#endif /* ODBCVER */
|
||||
|
||||
#define POSTGRESDRIVERVERSION "07.02.0001"
|
||||
|
||||
#ifdef WIN32
|
||||
#if (ODBCVER >= 0x0300)
|
||||
#ifdef UNICODE_SUPPORT
|
||||
|
@ -1,6 +1,7 @@
|
||||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
#include "version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -366,8 +367,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 7,2,0,01
|
||||
PRODUCTVERSION 7,2,0,01
|
||||
FILEVERSION PG_DRVFILE_VERSION
|
||||
PRODUCTVERSION PG_DRVFILE_VERSION
|
||||
FILEFLAGSMASK 0x3L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -389,14 +390,14 @@ BEGIN
|
||||
VALUE "CompanyName", "Insight Distribution Systems\0"
|
||||
#endif
|
||||
VALUE "FileDescription", "PostgreSQL Driver\0"
|
||||
VALUE "FileVersion", " 07.02.0001\0"
|
||||
VALUE "FileVersion", POSTGRES_RESOURCE_VERSION
|
||||
VALUE "InternalName", "psqlodbc\0"
|
||||
VALUE "LegalCopyright", "\0"
|
||||
VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
|
||||
VALUE "OriginalFilename", "psqlodbc.dll\0"
|
||||
VALUE "PrivateBuild", "\0"
|
||||
VALUE "ProductName", "Microsoft Open Database Connectivity\0"
|
||||
VALUE "ProductVersion", " 07.02.0001\0"
|
||||
VALUE "ProductVersion", POSTGRES_RESOURCE_VERSION
|
||||
VALUE "SpecialBuild", "\0"
|
||||
END
|
||||
END
|
||||
|
@ -110,9 +110,13 @@ QR_Constructor()
|
||||
rv->conn = NULL;
|
||||
rv->next = NULL;
|
||||
rv->inTuples = FALSE;
|
||||
rv->fcount = 0;
|
||||
rv->count_backend_allocated = 0;
|
||||
rv->count_keyset_allocated = 0;
|
||||
rv->num_total_rows = 0;
|
||||
rv->num_backend_rows = 0;
|
||||
rv->fetch_count = 0;
|
||||
rv->base = 0;
|
||||
rv->recent_processed_row_count = -1;
|
||||
rv->currTuple = -1;
|
||||
rv->num_fields = 0;
|
||||
rv->tupleField = NULL;
|
||||
@ -126,6 +130,9 @@ QR_Constructor()
|
||||
rv->rb_alloc = 0;
|
||||
rv->rb_count = 0;
|
||||
rv->rollback = NULL;
|
||||
rv->dl_alloc = 0;
|
||||
rv->dl_count = 0;
|
||||
rv->deleted = NULL;
|
||||
}
|
||||
|
||||
mylog("exit QR_Constructor\n");
|
||||
@ -202,14 +209,14 @@ QR_free_memory(QResultClass *self)
|
||||
register int lf,
|
||||
row;
|
||||
register TupleField *tuple = self->backend_tuples;
|
||||
int fcount = self->fcount;
|
||||
int num_backend_rows = self->num_backend_rows;
|
||||
int num_fields = self->num_fields;
|
||||
|
||||
mylog("QResult: free memory in, fcount=%d\n", fcount);
|
||||
mylog("QResult: free memory in, fcount=%d\n", num_backend_rows);
|
||||
|
||||
if (self->backend_tuples)
|
||||
{
|
||||
for (row = 0; row < fcount; row++)
|
||||
for (row = 0; row < num_backend_rows; row++)
|
||||
{
|
||||
mylog("row = %d, num_fields = %d\n", row, num_fields);
|
||||
for (lf = 0; lf < num_fields; lf++)
|
||||
@ -224,12 +231,14 @@ QR_free_memory(QResultClass *self)
|
||||
}
|
||||
|
||||
free(self->backend_tuples);
|
||||
self->count_backend_allocated = 0;
|
||||
self->backend_tuples = NULL;
|
||||
}
|
||||
if (self->keyset)
|
||||
{
|
||||
free(self->keyset);
|
||||
self->keyset = NULL;
|
||||
self->count_keyset_allocated = 0;
|
||||
}
|
||||
if (self->rollback)
|
||||
{
|
||||
@ -238,8 +247,16 @@ QR_free_memory(QResultClass *self)
|
||||
self->rb_count = 0;
|
||||
self->rollback = NULL;
|
||||
}
|
||||
if (self->deleted)
|
||||
{
|
||||
free(self->deleted);
|
||||
self->dl_alloc = 0;
|
||||
self->dl_count = 0;
|
||||
self->deleted = NULL;
|
||||
}
|
||||
|
||||
self->fcount = 0;
|
||||
self->num_total_rows = 0;
|
||||
self->num_backend_rows = 0;
|
||||
|
||||
mylog("QResult: free memory out\n");
|
||||
}
|
||||
@ -313,7 +330,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
|
||||
|
||||
/* allocate memory for the tuple cache */
|
||||
mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
|
||||
self->count_allocated = 0;
|
||||
self->count_backend_allocated = self->count_keyset_allocated = 0;
|
||||
if (self->num_fields > 0)
|
||||
{
|
||||
self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
|
||||
@ -323,15 +340,24 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
|
||||
QR_set_message(self, "Could not get memory for tuple cache.");
|
||||
return FALSE;
|
||||
}
|
||||
self->count_backend_allocated = tuple_size;
|
||||
}
|
||||
if (self->haskeyset)
|
||||
self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size);
|
||||
self->count_allocated = tuple_size;
|
||||
{
|
||||
if (self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size), !self->keyset)
|
||||
{
|
||||
self->status = PGRES_FATAL_ERROR;
|
||||
QR_set_message(self, "Could not get memory for tuple cache.");
|
||||
return FALSE;
|
||||
}
|
||||
self->count_keyset_allocated = tuple_size;
|
||||
}
|
||||
|
||||
self->inTuples = TRUE;
|
||||
|
||||
/* Force a read to occur in next_tuple */
|
||||
self->fcount = tuple_size + 1;
|
||||
self->num_total_rows = tuple_size + 1;
|
||||
self->num_backend_rows = tuple_size + 1;
|
||||
self->fetch_count = tuple_size + 1;
|
||||
self->base = 0;
|
||||
|
||||
@ -415,7 +441,7 @@ QR_next_tuple(QResultClass *self)
|
||||
|
||||
/* Speed up access */
|
||||
int fetch_count = self->fetch_count;
|
||||
int fcount = self->fcount;
|
||||
int num_backend_rows = self->num_backend_rows;
|
||||
int fetch_size,
|
||||
offset = 0;
|
||||
int end_tuple = self->rowset_size + self->base;
|
||||
@ -430,21 +456,21 @@ QR_next_tuple(QResultClass *self)
|
||||
char fetch[128];
|
||||
QueryInfo qi;
|
||||
ConnInfo *ci = NULL;
|
||||
BOOL set_no_trans;
|
||||
UDWORD abort_opt;
|
||||
|
||||
if (fetch_count < fcount)
|
||||
if (fetch_count < num_backend_rows)
|
||||
{
|
||||
/* return a row from cache */
|
||||
mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount);
|
||||
mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, num_backend_rows);
|
||||
self->tupleField = the_tuples + (fetch_count * self->num_fields); /* next row */
|
||||
self->fetch_count++;
|
||||
return TRUE;
|
||||
}
|
||||
else if (self->fcount < self->cache_size)
|
||||
else if (self->num_backend_rows < self->cache_size)
|
||||
{
|
||||
/* last row from cache */
|
||||
/* We are done because we didn't even get CACHE_SIZE tuples */
|
||||
mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", fcount, fetch_count);
|
||||
mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", num_backend_rows, fetch_count);
|
||||
self->tupleField = NULL;
|
||||
self->status = PGRES_END_TUPLES;
|
||||
/* end of tuples */
|
||||
@ -464,13 +490,13 @@ QR_next_tuple(QResultClass *self)
|
||||
ci = &(self->conn->connInfo);
|
||||
if (!self->cursor || !ci->drivers.use_declarefetch)
|
||||
{
|
||||
mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count);
|
||||
mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", self->num_total_rows, fetch_count);
|
||||
self->tupleField = NULL;
|
||||
self->status = PGRES_END_TUPLES;
|
||||
return -1; /* end of tuples */
|
||||
}
|
||||
|
||||
if (self->base == fcount)
|
||||
if (self->base == num_backend_rows)
|
||||
{
|
||||
/* not a correction */
|
||||
/* Determine the optimum cache size. */
|
||||
@ -489,7 +515,7 @@ QR_next_tuple(QResultClass *self)
|
||||
/* need to correct */
|
||||
corrected = TRUE;
|
||||
|
||||
fetch_size = end_tuple - fcount;
|
||||
fetch_size = end_tuple - num_backend_rows;
|
||||
|
||||
self->cache_size += fetch_size;
|
||||
|
||||
@ -497,9 +523,9 @@ QR_next_tuple(QResultClass *self)
|
||||
self->fetch_count++;
|
||||
}
|
||||
|
||||
if (!self->backend_tuples || self->cache_size > self->count_allocated)
|
||||
if (!self->backend_tuples || self->cache_size > self->count_backend_allocated)
|
||||
{
|
||||
self->count_allocated = 0;
|
||||
self->count_backend_allocated = 0;
|
||||
if (self->num_fields > 0)
|
||||
{
|
||||
self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
|
||||
@ -510,10 +536,14 @@ QR_next_tuple(QResultClass *self)
|
||||
QR_set_message(self, "Out of memory while reading tuples.");
|
||||
return FALSE;
|
||||
}
|
||||
self->count_backend_allocated = self->cache_size;
|
||||
}
|
||||
if (self->haskeyset)
|
||||
}
|
||||
if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated))
|
||||
{
|
||||
self->count_keyset_allocated = 0;
|
||||
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size);
|
||||
self->count_allocated = self->cache_size;
|
||||
self->count_keyset_allocated = self->cache_size;
|
||||
}
|
||||
sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
|
||||
|
||||
@ -534,7 +564,7 @@ QR_next_tuple(QResultClass *self)
|
||||
}
|
||||
else
|
||||
{
|
||||
mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count);
|
||||
mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->num_backend_rows, self->fetch_count);
|
||||
|
||||
/*
|
||||
* This is a pre-fetch (fetching rows right after query but
|
||||
@ -548,7 +578,8 @@ QR_next_tuple(QResultClass *self)
|
||||
if (!corrected)
|
||||
{
|
||||
self->base = 0;
|
||||
self->fcount = 0;
|
||||
self->num_total_rows = 0; /* right ? */
|
||||
self->num_backend_rows = 0;
|
||||
}
|
||||
|
||||
sock = CC_get_socket(self->conn);
|
||||
@ -569,14 +600,15 @@ QR_next_tuple(QResultClass *self)
|
||||
case 'B': /* Tuples in binary format */
|
||||
case 'D': /* Tuples in ASCII format */
|
||||
|
||||
if ((!self->cursor || !ci->drivers.use_declarefetch) && self->fcount >= self->count_allocated)
|
||||
if (!self->cursor || !ci->drivers.use_declarefetch)
|
||||
{
|
||||
int tuple_size = self->count_allocated;
|
||||
if (self->num_fields > 0 &&
|
||||
self->num_total_rows >= self->count_backend_allocated)
|
||||
{
|
||||
int tuple_size = self->count_backend_allocated;
|
||||
|
||||
mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
|
||||
tuple_size *= 2;
|
||||
if (self->num_fields > 0)
|
||||
{
|
||||
self->backend_tuples = (TupleField *) realloc(self->backend_tuples,
|
||||
tuple_size * self->num_fields * sizeof(TupleField));
|
||||
if (!self->backend_tuples)
|
||||
@ -585,10 +617,16 @@ QR_next_tuple(QResultClass *self)
|
||||
QR_set_message(self, "Out of memory while reading tuples.");
|
||||
return FALSE;
|
||||
}
|
||||
self->count_backend_allocated = tuple_size;
|
||||
}
|
||||
if (self->haskeyset)
|
||||
if (self->haskeyset &&
|
||||
self->num_total_rows >= self->count_keyset_allocated)
|
||||
{
|
||||
int tuple_size = self->count_keyset_allocated;
|
||||
tuple_size *= 2;
|
||||
self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size);
|
||||
self->count_allocated = tuple_size;
|
||||
self->count_keyset_allocated = tuple_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!QR_read_tuple(self, (char) (id == 0)))
|
||||
@ -597,7 +635,9 @@ QR_next_tuple(QResultClass *self)
|
||||
QR_set_message(self, "Error reading the tuple");
|
||||
return FALSE;
|
||||
}
|
||||
self->fcount++;
|
||||
self->num_total_rows++;
|
||||
if (self->num_fields > 0)
|
||||
self->num_backend_rows++;
|
||||
break; /* continue reading */
|
||||
|
||||
case 'C': /* End of tuple list */
|
||||
@ -607,10 +647,10 @@ QR_next_tuple(QResultClass *self)
|
||||
mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
|
||||
|
||||
self->inTuples = FALSE;
|
||||
if (self->fcount > 0)
|
||||
if (self->num_total_rows > 0)
|
||||
{
|
||||
qlog(" [ fetched %d rows ]\n", self->fcount);
|
||||
mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount);
|
||||
qlog(" [ fetched %d rows ]\n", self->num_total_rows);
|
||||
mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->num_total_rows);
|
||||
|
||||
/* set to first row */
|
||||
self->tupleField = self->backend_tuples + (offset * self->num_fields);
|
||||
@ -629,11 +669,15 @@ QR_next_tuple(QResultClass *self)
|
||||
QR_set_message(self, msgbuffer);
|
||||
self->status = PGRES_FATAL_ERROR;
|
||||
|
||||
set_no_trans = FALSE;
|
||||
abort_opt = 0;
|
||||
if (!strncmp(msgbuffer, "FATAL", 5))
|
||||
set_no_trans = TRUE;
|
||||
CC_on_abort(self->conn, set_no_trans);
|
||||
abort_opt = NO_TRANS | CONN_DEAD;
|
||||
CC_on_abort(self->conn, abort_opt);
|
||||
QR_set_status(self, PGRES_FATAL_ERROR);
|
||||
QR_set_message(self, msgbuffer);
|
||||
QR_set_aborted(self, TRUE);
|
||||
|
||||
mylog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
|
||||
qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
|
||||
|
||||
return FALSE;
|
||||
@ -651,7 +695,7 @@ QR_next_tuple(QResultClass *self)
|
||||
qlog("QR_next_tuple: Unexpected result from backend: id = '%c' (%d)\n", id, id);
|
||||
QR_set_message(self, "Unexpected result from backend. It probably crashed");
|
||||
self->status = PGRES_FATAL_ERROR;
|
||||
CC_on_abort(self->conn, TRUE);
|
||||
CC_on_abort(self->conn, NO_TRANS | CONN_DEAD);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -681,16 +725,16 @@ QR_read_tuple(QResultClass *self, char binary)
|
||||
|
||||
/* set the current row to read the fields into */
|
||||
effective_cols = ci_num_fields;
|
||||
this_tuplefield = self->backend_tuples + (self->fcount * num_fields);
|
||||
this_tuplefield = self->backend_tuples + (self->num_backend_rows * num_fields);
|
||||
if (self->haskeyset)
|
||||
{
|
||||
this_keyset = self->keyset + self->fcount;
|
||||
this_keyset = self->keyset + self->num_total_rows;
|
||||
this_keyset->status = 0;
|
||||
effective_cols -= 2;
|
||||
}
|
||||
|
||||
bitmaplen = (Int2) num_fields / BYTELEN;
|
||||
if ((num_fields % BYTELEN) > 0)
|
||||
bitmaplen = (Int2) ci_num_fields / BYTELEN;
|
||||
if ((ci_num_fields % BYTELEN) > 0)
|
||||
bitmaplen++;
|
||||
|
||||
/*
|
||||
|
@ -48,15 +48,18 @@ struct QResultClass_
|
||||
QResultClass *next; /* the following result class */
|
||||
|
||||
/* Stuff for declare/fetch tuples */
|
||||
int count_allocated; /* m(re)alloced count */
|
||||
int num_total_rows; /* total count of rows read in */
|
||||
int count_backend_allocated;/* m(re)alloced count */
|
||||
int count_keyset_allocated; /* m(re)alloced count */
|
||||
int num_backend_rows; /* count of tuples kept in backend_tuples member */
|
||||
int fetch_count; /* logical rows read so far */
|
||||
int fcount; /* actual rows read in the fetch */
|
||||
int currTuple;
|
||||
int base;
|
||||
|
||||
int num_fields; /* number of fields in the result */
|
||||
int cache_size;
|
||||
int rowset_size;
|
||||
Int4 recent_processed_row_count;
|
||||
|
||||
QueryResultCode status;
|
||||
|
||||
@ -77,6 +80,9 @@ struct QResultClass_
|
||||
UInt2 rb_alloc; /* count of allocated rollback info */
|
||||
UInt2 rb_count; /* count of rollback info */
|
||||
Rollback *rollback;
|
||||
UInt2 dl_alloc; /* count of allocated deleted info */
|
||||
UInt2 dl_count; /* count of deleted info */
|
||||
UInt4 *deleted;
|
||||
};
|
||||
|
||||
#define QR_get_fields(self) (self->fields)
|
||||
@ -96,7 +102,8 @@ struct QResultClass_
|
||||
#define QR_get_field_type(self, fieldno_) (CI_get_oid(self->fields, fieldno_))
|
||||
|
||||
/* These functions are used only for manual result sets */
|
||||
#define QR_get_num_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->fcount)
|
||||
#define QR_get_num_total_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_total_rows)
|
||||
#define QR_get_num_backend_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_backend_rows)
|
||||
#define QR_add_tuple(self, new_tuple) (TL_add_tuple(self->manual_tuples, new_tuple))
|
||||
#define QR_set_field_info(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1))
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -272,7 +272,7 @@ SC_Constructor(void)
|
||||
rv->rowset_start = -1;
|
||||
rv->current_col = -1;
|
||||
rv->bind_row = 0;
|
||||
rv->last_fetch_count = 0;
|
||||
rv->last_fetch_count = rv->last_fetch_count_include_ommitted = 0;
|
||||
rv->save_rowset_size = -1;
|
||||
|
||||
rv->data_at_exec = -1;
|
||||
@ -302,6 +302,7 @@ SC_Constructor(void)
|
||||
rv->miscinfo = 0;
|
||||
rv->updatable = FALSE;
|
||||
rv->error_recsize = -1;
|
||||
rv->diag_row_count = 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@ -533,7 +534,7 @@ SC_recycle_statement(StatementClass *self)
|
||||
self->rowset_start = -1;
|
||||
self->current_col = -1;
|
||||
self->bind_row = 0;
|
||||
self->last_fetch_count = 0;
|
||||
self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
|
||||
|
||||
self->errormsg = NULL;
|
||||
self->errornumber = 0;
|
||||
@ -619,6 +620,7 @@ SC_clear_error(StatementClass *self)
|
||||
self->errormsg_created = FALSE;
|
||||
self->errorpos = 0;
|
||||
self->error_recsize = -1;
|
||||
self->diag_row_count = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -733,21 +735,21 @@ SC_fetch(StatementClass *self)
|
||||
/* TupleField *tupleField; */
|
||||
ConnInfo *ci = &(SC_get_conn(self)->connInfo);
|
||||
|
||||
self->last_fetch_count = 0;
|
||||
self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
|
||||
coli = QR_get_fields(res); /* the column info */
|
||||
|
||||
mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch);
|
||||
|
||||
if (self->manual_result || !SC_is_fetchcursor(self))
|
||||
{
|
||||
if (self->currTuple >= QR_get_num_tuples(res) - 1 ||
|
||||
if (self->currTuple >= QR_get_num_total_tuples(res) - 1 ||
|
||||
(self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
|
||||
{
|
||||
/*
|
||||
* if at the end of the tuples, return "no data found" and set
|
||||
* the cursor past the end of the result set
|
||||
*/
|
||||
self->currTuple = QR_get_num_tuples(res);
|
||||
self->currTuple = QR_get_num_total_tuples(res);
|
||||
return SQL_NO_DATA_FOUND;
|
||||
}
|
||||
|
||||
@ -774,11 +776,23 @@ SC_fetch(StatementClass *self)
|
||||
return SQL_ERROR;
|
||||
}
|
||||
}
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
if (res->haskeyset)
|
||||
{
|
||||
UWORD pstatus = res->keyset[self->currTuple].status;
|
||||
if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
|
||||
return SQL_SUCCESS_WITH_INFO;
|
||||
if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
|
||||
0 != (pstatus & CURS_OTHER_DELETED))
|
||||
return SQL_SUCCESS_WITH_INFO;
|
||||
}
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
|
||||
num_cols = QR_NumResultCols(res);
|
||||
|
||||
result = SQL_SUCCESS;
|
||||
self->last_fetch_count = 1;
|
||||
self->last_fetch_count++;
|
||||
self->last_fetch_count_include_ommitted++;
|
||||
|
||||
opts = SC_get_ARD(self);
|
||||
/*
|
||||
@ -830,7 +844,12 @@ SC_fetch(StatementClass *self)
|
||||
else if (SC_is_fetchcursor(self))
|
||||
value = QR_get_value_backend(res, lf);
|
||||
else
|
||||
value = QR_get_value_backend_row(res, self->currTuple, lf);
|
||||
{
|
||||
int curt = res->base;
|
||||
if (self->rowset_start >= 0)
|
||||
curt += (self->currTuple - self->rowset_start);
|
||||
value = QR_get_value_backend_row(res, curt, lf);
|
||||
}
|
||||
|
||||
mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
|
||||
|
||||
@ -1152,7 +1171,7 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self)
|
||||
if (res)
|
||||
{
|
||||
qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
|
||||
qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor));
|
||||
qlog(" fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->num_total_rows, res->num_fields, nullcheck(res->cursor));
|
||||
qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
|
||||
qlog(" status=%d, inTuples=%d\n", res->status, res->inTuples);
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ typedef enum
|
||||
#define STMT_ERROR_IN_ROW 30
|
||||
#define STMT_INVALID_DESCRIPTOR_IDENTIFIER 31
|
||||
#define STMT_OPTION_NOT_FOR_THE_DRIVER 32
|
||||
#define STMT_FETCH_OUT_OF_RANGE 33
|
||||
|
||||
/* statement types */
|
||||
enum
|
||||
@ -137,15 +138,6 @@ struct StatementClass_
|
||||
char *errormsg;
|
||||
int errornumber;
|
||||
|
||||
/* information on bindings */
|
||||
/*** BindInfoClass *bindings; ***/ /* array to store the binding information */
|
||||
/*** BindInfoClass bookmark;
|
||||
int bindings_allocated; ***/
|
||||
|
||||
/* information on statement parameters */
|
||||
/*** int parameters_allocated;
|
||||
ParameterInfoClass *parameters; ***/
|
||||
|
||||
Int4 currTuple; /* current absolute row number (GetData,
|
||||
* SetPos, SQLFetch) */
|
||||
int save_rowset_size; /* saved rowset size in case of
|
||||
@ -200,9 +192,11 @@ struct StatementClass_
|
||||
char updatable;
|
||||
SWORD errorpos;
|
||||
SWORD error_recsize;
|
||||
Int4 diag_row_count;
|
||||
char *load_statement; /* to (re)load updatable individual rows */
|
||||
Int4 from_pos;
|
||||
Int4 where_pos;
|
||||
Int4 last_fetch_count_include_ommitted;
|
||||
};
|
||||
|
||||
#define SC_get_conn(a) (a->hdbc)
|
||||
|
@ -53,6 +53,8 @@ struct Rollback_
|
||||
#define CURS_SELF_DELETED (1L << 7)
|
||||
#define CURS_SELF_UPDATED (1L << 8)
|
||||
#define CURS_NEEDS_REREAD (1L << 9)
|
||||
#define CURS_IN_ROWSET (1L << 10)
|
||||
#define CURS_OTHER_DELETED (1L << 11)
|
||||
|
||||
/* These macros are wrappers for the corresponding set_tuplefield functions
|
||||
but these handle automatic NULL determination and call set_tuplefield_null()
|
||||
|
Loading…
x
Reference in New Issue
Block a user