The version is now 7.01.0010.
1) Handle parameter array. 2) Allow re-use of the connection handle after SQLDisconnect. 3) Reject NULL if no indicator specified. 4) Improve the handling of '_' in table name. 5) Unify internal begin/commit/abort operations. 6) Change SQLTables() to return null not "" for the table_owner. 7) Fix a bug about parameter handling reported by Benoit Menendez. 8) Add cast in handling ODBC date/time escape sequences. 9) Fix a bug about cache_size handing in declare/fetch mode. [ODBC3.0 related] 10) Improve the handling of descriptor handles(ODBC3.0). 11) Improve the type handling of some types for ODBC3.0. [Thanks to Marcelo Aceto for his useful patches] 12) Allow nested ODBC escape. 13) Allow changing autocommit on/off inside the transaction block. 14) Improve the handling of ODBC scalar functions.
This commit is contained in:
parent
b6db89a02d
commit
3c16d095b5
@ -134,6 +134,8 @@ PGAPI_BindParameter(
|
||||
stmt->parameters[ipar].EXEC_buffer = NULL;
|
||||
}
|
||||
|
||||
if (pcbValue && stmt->options.param_offset_ptr)
|
||||
pcbValue += (*stmt->options.param_offset_ptr >> 2);
|
||||
/* Data at exec macro only valid for C char/binary data */
|
||||
if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
|
||||
*pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
|
||||
|
@ -309,12 +309,6 @@ CC_Destructor(ConnectionClass *self)
|
||||
|
||||
mylog("after CC_Cleanup\n");
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
if (self->client_encoding)
|
||||
free(self->client_encoding);
|
||||
if (self->server_encoding)
|
||||
free(self->server_encoding);
|
||||
#endif /* MULTIBYTE */
|
||||
/* Free up statement holders */
|
||||
if (self->stmts)
|
||||
{
|
||||
@ -323,23 +317,6 @@ CC_Destructor(ConnectionClass *self)
|
||||
}
|
||||
mylog("after free statement holders\n");
|
||||
|
||||
/* Free cached table info */
|
||||
if (self->col_info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < self->ntables; i++)
|
||||
{
|
||||
if (self->col_info[i]->result) /* Free the SQLColumns
|
||||
* result structure */
|
||||
QR_Destructor(self->col_info[i]->result);
|
||||
|
||||
free(self->col_info[i]);
|
||||
}
|
||||
free(self->col_info);
|
||||
}
|
||||
|
||||
|
||||
free(self);
|
||||
|
||||
mylog("exit CC_Destructor\n");
|
||||
@ -380,6 +357,59 @@ CC_clear_error(ConnectionClass *self)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Used to begin a transaction.
|
||||
*/
|
||||
char
|
||||
CC_begin(ConnectionClass *self)
|
||||
{
|
||||
char ret = TRUE;
|
||||
if (!CC_is_in_trans(self))
|
||||
{
|
||||
QResultClass *res = CC_send_query(self, "BEGIN", NULL);
|
||||
mylog("CC_begin: sending BEGIN!\n");
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
ret = (!QR_aborted(res) && QR_command_successful(res));
|
||||
QR_Destructor(res);
|
||||
if (ret)
|
||||
CC_set_in_trans(self);
|
||||
}
|
||||
else
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to commit a transaction.
|
||||
* We are almost always in the middle of a transaction.
|
||||
*/
|
||||
char
|
||||
CC_commit(ConnectionClass *self)
|
||||
{
|
||||
char ret = FALSE;
|
||||
if (CC_is_in_trans(self))
|
||||
{
|
||||
QResultClass *res = CC_send_query(self, "COMMIT", NULL);
|
||||
mylog("CC_commit: sending COMMIT!\n");
|
||||
|
||||
CC_set_no_trans(self);
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
ret = QR_command_successful(res);
|
||||
QR_Destructor(res);
|
||||
}
|
||||
else
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to cancel a transaction.
|
||||
* We are almost always in the middle of a transaction.
|
||||
@ -387,22 +417,17 @@ CC_clear_error(ConnectionClass *self)
|
||||
char
|
||||
CC_abort(ConnectionClass *self)
|
||||
{
|
||||
QResultClass *res;
|
||||
|
||||
if (CC_is_in_trans(self))
|
||||
{
|
||||
res = NULL;
|
||||
|
||||
QResultClass *res = CC_send_query(self, "ROLLBACK", NULL);
|
||||
mylog("CC_abort: sending ABORT!\n");
|
||||
|
||||
res = CC_send_query(self, "ABORT", NULL);
|
||||
CC_set_no_trans(self);
|
||||
|
||||
if (res != NULL)
|
||||
QR_Destructor(res);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -461,6 +486,37 @@ CC_cleanup(ConnectionClass *self)
|
||||
}
|
||||
#endif
|
||||
|
||||
self->status = CONN_NOT_CONNECTED;
|
||||
self->transact_status = CONN_IN_AUTOCOMMIT;
|
||||
memset(&self->connInfo, 0, sizeof(ConnInfo));
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
self->connInfo.updatable_cursors = 1;
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
memcpy(&(self->connInfo.drivers), &globals, sizeof(globals));
|
||||
#ifdef MULTIBYTE
|
||||
if (self->client_encoding)
|
||||
free(self->client_encoding);
|
||||
self->client_encoding = NULL;
|
||||
if (self->server_encoding)
|
||||
free(self->server_encoding);
|
||||
self->server_encoding = NULL;
|
||||
#endif /* MULTIBYTE */
|
||||
/* Free cached table info */
|
||||
if (self->col_info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < self->ntables; i++)
|
||||
{
|
||||
if (self->col_info[i]->result) /* Free the SQLColumns result structure */
|
||||
QR_Destructor(self->col_info[i]->result);
|
||||
|
||||
free(self->col_info[i]);
|
||||
}
|
||||
free(self->col_info);
|
||||
self->col_info = NULL;
|
||||
}
|
||||
self->ntables = 0;
|
||||
mylog("exit CC_Cleanup\n");
|
||||
return TRUE;
|
||||
}
|
||||
@ -516,7 +572,6 @@ md5_auth_send(ConnectionClass *self, const char *salt)
|
||||
ConnInfo *ci = &(self->connInfo);
|
||||
SocketClass *sock = self->sock;
|
||||
|
||||
mylog("MD5 user=%s password=%s\n", ci->username, ci->password);
|
||||
if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1)))
|
||||
return 1;
|
||||
if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1))
|
||||
@ -601,9 +656,10 @@ CC_connect(ConnectionClass *self, char do_password)
|
||||
ci->drivers.conn_settings,
|
||||
encoding ? encoding : "");
|
||||
#else
|
||||
qlog(" extra_systable_prefixes='%s', conn_settings='%s'\n",
|
||||
qlog(" extra_systable_prefixes='%s', conn_settings='%s', protocol='%s'\n",
|
||||
ci->drivers.extra_systable_prefixes,
|
||||
ci->drivers.conn_settings);
|
||||
ci->drivers.conn_settings,
|
||||
ci->protocol);
|
||||
#endif
|
||||
|
||||
if (self->status != CONN_NOT_CONNECTED)
|
||||
@ -1037,7 +1093,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
|
||||
ReadyToReturn,
|
||||
tuples_return = FALSE,
|
||||
query_completed = FALSE,
|
||||
before_64 = PG_VERSION_LT(self, 6.4);
|
||||
before_64 = PG_VERSION_LT(self, 6.4),
|
||||
used_passed_result_object = FALSE;
|
||||
|
||||
/* ERROR_MSG_LENGTH is suffcient */
|
||||
static char msgbuffer[ERROR_MSG_LENGTH + 1];
|
||||
@ -1289,6 +1346,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
|
||||
else
|
||||
{ /* next fetch, so reuse an existing result */
|
||||
|
||||
used_passed_result_object = TRUE;
|
||||
/*
|
||||
* called from QR_next_tuple and must return
|
||||
* immediately.
|
||||
@ -1373,9 +1431,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
|
||||
QR_Destructor(res);
|
||||
if (result_in && retres != result_in)
|
||||
{
|
||||
if (qi && qi->result_in)
|
||||
;
|
||||
else
|
||||
if (!used_passed_result_object)
|
||||
QR_Destructor(result_in);
|
||||
}
|
||||
return retres;
|
||||
|
@ -292,6 +292,8 @@ ConnectionClass *CC_Constructor(void);
|
||||
char CC_Destructor(ConnectionClass *self);
|
||||
int CC_cursor_count(ConnectionClass *self);
|
||||
char CC_cleanup(ConnectionClass *self);
|
||||
char CC_begin(ConnectionClass *self);
|
||||
char CC_commit(ConnectionClass *self);
|
||||
char CC_abort(ConnectionClass *self);
|
||||
int CC_set_translation(ConnectionClass *self);
|
||||
char CC_connect(ConnectionClass *self, char do_password);
|
||||
|
@ -51,77 +51,80 @@
|
||||
* - thomas 2000-04-03
|
||||
*/
|
||||
char *mapFuncs[][2] = {
|
||||
/* { "ASCII", "ascii" }, */
|
||||
{"CHAR", "chr"},
|
||||
{"CONCAT", "textcat"},
|
||||
/* { "DIFFERENCE", "difference" }, */
|
||||
/* { "INSERT", "insert" }, */
|
||||
{"LCASE", "lower"},
|
||||
{"LEFT", "ltrunc"},
|
||||
{"LOCATE", "strpos"},
|
||||
{"LENGTH", "char_length"},
|
||||
/* { "LTRIM", "ltrim" }, */
|
||||
{"RIGHT", "rtrunc"},
|
||||
/* { "REPEAT", "repeat" }, */
|
||||
/* { "REPLACE", "replace" }, */
|
||||
/* { "RTRIM", "rtrim" }, */
|
||||
/* { "SOUNDEX", "soundex" }, */
|
||||
{"SUBSTRING", "substr"},
|
||||
{"UCASE", "upper"},
|
||||
/* { "ASCII", "ascii" }, built_in */
|
||||
{"CHAR", "chr($*)" },
|
||||
{"CONCAT", "textcat($*)" },
|
||||
/* { "DIFFERENCE", "difference" }, how to ? */
|
||||
{"INSERT", "substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3)" },
|
||||
{"LCASE", "lower($*)" },
|
||||
{"LEFT", "ltrunc($*)" },
|
||||
{"%2LOCATE", "strpos($2, $1)" }, /* 2 parameters */
|
||||
{"%3LOCATE", "strpos(substring($2 from $3), $1) + $3 - 1" }, /* 3 parameters */
|
||||
{"LENGTH", "char_length($*)"},
|
||||
/* { "LTRIM", "ltrim" }, built_in */
|
||||
{"RIGHT", "rtrunc($*)" },
|
||||
{"SPACE", "repeat('' '', $1)" },
|
||||
/* { "REPEAT", "repeat" }, built_in */
|
||||
/* { "REPLACE", "replace" }, ??? */
|
||||
/* { "RTRIM", "rtrim" }, built_in */
|
||||
/* { "SOUNDEX", "soundex" }, how to ? */
|
||||
{"SUBSTRING", "substr($*)" },
|
||||
{"UCASE", "upper($*)" },
|
||||
|
||||
/* { "ABS", "abs" }, */
|
||||
/* { "ACOS", "acos" }, */
|
||||
/* { "ASIN", "asin" }, */
|
||||
/* { "ATAN", "atan" }, */
|
||||
/* { "ATAN2", "atan2" }, */
|
||||
{"CEILING", "ceil"},
|
||||
/* { "COS", "cos" }, */
|
||||
/* { "COT", "cot" }, */
|
||||
/* { "DEGREES", "degrees" }, */
|
||||
/* { "EXP", "exp" }, */
|
||||
/* { "FLOOR", "floor" }, */
|
||||
{"LOG", "ln"},
|
||||
{"LOG10", "log"},
|
||||
/* { "MOD", "mod" }, */
|
||||
/* { "PI", "pi" }, */
|
||||
{"POWER", "pow"},
|
||||
/* { "RADIANS", "radians" }, */
|
||||
{"RAND", "random"},
|
||||
/* { "ROUND", "round" }, */
|
||||
/* { "SIGN", "sign" }, */
|
||||
/* { "SIN", "sin" }, */
|
||||
/* { "SQRT", "sqrt" }, */
|
||||
/* { "TAN", "tan" }, */
|
||||
{"TRUNCATE", "trunc"},
|
||||
/* { "ABS", "abs" }, built_in */
|
||||
/* { "ACOS", "acos" }, built_in */
|
||||
/* { "ASIN", "asin" }, built_in */
|
||||
/* { "ATAN", "atan" }, built_in */
|
||||
/* { "ATAN2", "atan2" }, bui;t_in */
|
||||
{"CEILING", "ceil($*)" },
|
||||
/* { "COS", "cos" }, built_in */
|
||||
/* { "COT", "cot" }, built_in */
|
||||
/* { "DEGREES", "degrees" }, built_in */
|
||||
/* { "EXP", "exp" }, built_in */
|
||||
/* { "FLOOR", "floor" }, built_in */
|
||||
{"LOG", "ln($*)" },
|
||||
{"LOG10", "log($*)" },
|
||||
/* { "MOD", "mod" }, built_in */
|
||||
/* { "PI", "pi" }, built_in */
|
||||
{"POWER", "pow($*)" },
|
||||
/* { "RADIANS", "radians" }, built_in */
|
||||
{"%0RAND", "random()" }, /* 0 parameters */
|
||||
{"%1RAND", "(setseed($1) * .0 + random())" }, /* 1 parameters */
|
||||
/* { "ROUND", "round" }, built_in */
|
||||
/* { "SIGN", "sign" }, built_in */
|
||||
/* { "SIN", "sin" }, built_in */
|
||||
/* { "SQRT", "sqrt" }, built_in */
|
||||
/* { "TAN", "tan" }, built_in */
|
||||
{"TRUNCATE", "trunc($*)" },
|
||||
|
||||
{"CURRENT_DATE", "curdate"},
|
||||
{"CURRENT_TIME", "curtime"},
|
||||
{"CURRENT_TIMESTAMP", "odbc_timestamp"},
|
||||
{"CURRENT_USER", "odbc_current_user"},
|
||||
{"SESSION_USER", "odbc_session_user"},
|
||||
/* { "CURDATE", "curdate" }, */
|
||||
/* { "CURTIME", "curtime" }, */
|
||||
/* { "DAYNAME", "dayname" }, */
|
||||
/* { "DAYOFMONTH", "dayofmonth" }, */
|
||||
/* { "DAYOFWEEK", "dayofweek" }, */
|
||||
/* { "DAYOFYEAR", "dayofyear" }, */
|
||||
/* { "HOUR", "hour" }, */
|
||||
/* { "MINUTE", "minute" }, */
|
||||
/* { "MONTH", "month" }, */
|
||||
/* { "MONTHNAME", "monthname" }, */
|
||||
/* { "NOW", "now" }, */
|
||||
/* { "QUARTER", "quarter" }, */
|
||||
/* { "SECOND", "second" }, */
|
||||
/* { "WEEK", "week" }, */
|
||||
/* { "YEAR", "year" }, */
|
||||
{"CURRENT_DATE", "current_date" },
|
||||
{"CURRENT_TIME", "current_time" },
|
||||
{"CURRENT_TIMESTAMP", "current_timestamp" },
|
||||
{"CURRENT_USER", "cast(current_user as text)" },
|
||||
{"SESSION_USER", "cast(session_user as text)" },
|
||||
{"CURDATE", "current_date" },
|
||||
{"CURTIME", "current_time" },
|
||||
{"DAYNAME", "to_char($1, 'Day')" },
|
||||
{"DAYOFMONTH", "cast(extract(day from $1) as integer)" },
|
||||
{"DAYOFWEEK", "(cast(extract(dow from $1) as integer) + 1)" },
|
||||
{"DAYOFYEAR", "cast(extract(doy from $1) as integer)" },
|
||||
{"HOUR", "cast(extract(hour from $1) as integer)" },
|
||||
{"MINUTE", "cast(extract(minute from $1) as integer)" },
|
||||
{"MONTH", "cast(extract(month from $1) as integer)" },
|
||||
{"MONTHNAME", " to_char($1, 'Month')" },
|
||||
/* { "NOW", "now" }, built_in */
|
||||
{"QUARTER", "cast(extract(quarter from $1) as integer)" },
|
||||
{"SECOND", "cast(extract(second from $1) as integer)" },
|
||||
{"WEEK", "cast(extract(week from $1) as integer)" },
|
||||
{"YEAR", "cast(extract(year from $1) as integer)" },
|
||||
|
||||
/* { "DATABASE", "database" }, */
|
||||
{"IFNULL", "coalesce"},
|
||||
{"USER", "odbc_user"},
|
||||
{"IFNULL", "coalesce($*)" },
|
||||
{"USER", "cast(current_user as text)" },
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static char *mapFunction(const char *func);
|
||||
static const char *mapFunction(const char *func, int param_count);
|
||||
static unsigned int conv_from_octal(const unsigned char *s);
|
||||
static unsigned int conv_from_hex(const unsigned char *s);
|
||||
static char *conv_to_octal(unsigned char val);
|
||||
@ -307,9 +310,10 @@ int
|
||||
copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
|
||||
{
|
||||
BindInfoClass *bic = &(stmt->bindings[col]);
|
||||
UInt4 offset = stmt->options.row_offset_ptr ? *stmt->options.row_offset_ptr : 0;
|
||||
|
||||
return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) bic->buffer,
|
||||
(SDWORD) bic->buflen, (SDWORD *) bic->used);
|
||||
return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) (bic->buffer + offset),
|
||||
(SDWORD) bic->buflen, (SDWORD *) (bic->used + (offset >> 2)));
|
||||
}
|
||||
|
||||
|
||||
@ -318,6 +322,7 @@ int
|
||||
copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
|
||||
PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
|
||||
{
|
||||
static char *func = "copy_and_convert_field";
|
||||
Int4 len = 0,
|
||||
copy_len = 0;
|
||||
SIMPLE_TIME st;
|
||||
@ -387,8 +392,17 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
|
||||
* doing nothing to the buffer.
|
||||
*/
|
||||
if (pcbValue)
|
||||
{
|
||||
*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = SQL_NULL_DATA;
|
||||
return COPY_OK;
|
||||
return COPY_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt->errornumber = STMT_RETURN_NULL_WITHOUT_INDICATOR;
|
||||
stmt->errormsg = "StrLen_or_IndPtr was a null pointer and NULL data was retrieved";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (stmt->hdbc->DataSourceToDriver != NULL)
|
||||
@ -863,6 +877,26 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
|
||||
*((UDWORD *) rgbValue + bind_row) = atol(neut_str);
|
||||
break;
|
||||
|
||||
#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
|
||||
#ifdef WIN32
|
||||
case SQL_C_SBIGINT:
|
||||
len = 8;
|
||||
if (bind_size > 0)
|
||||
*(SQLBIGINT *) ((char *) rgbValue + (bind_row * bind_size)) = _atoi64(neut_str);
|
||||
else
|
||||
*((SQLBIGINT *) rgbValue + bind_row) = _atoi64(neut_str);
|
||||
break;
|
||||
|
||||
case SQL_C_UBIGINT:
|
||||
len = 8;
|
||||
if (bind_size > 0)
|
||||
*(SQLUBIGINT *) ((char *) rgbValue + (bind_row * bind_size)) = _atoi64(neut_str);
|
||||
else
|
||||
*((SQLUBIGINT *) rgbValue + bind_row) = _atoi64(neut_str);
|
||||
break;
|
||||
|
||||
#endif /* WIN32 */
|
||||
#endif /* ODBCINT64 */
|
||||
case SQL_C_BINARY:
|
||||
|
||||
/* truncate if necessary */
|
||||
@ -1146,6 +1180,11 @@ table_for_update(const char *stmt, int *endpos)
|
||||
return !wstmt[0] || isspace((unsigned char) wstmt[0]);
|
||||
}
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
#define my_strchr(s1,c1) multibyte_strchr(s1,c1)
|
||||
#else
|
||||
#define my_strchr(s1,c1) strchr(s1,c1)
|
||||
#endif
|
||||
/*
|
||||
* This function inserts parameters into an SQL statements.
|
||||
* It will also modify a SELECT statement for use with declare/fetch cursors.
|
||||
@ -1193,10 +1232,13 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
char token_save[64];
|
||||
int token_len;
|
||||
BOOL prev_token_end;
|
||||
UInt4 offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
|
||||
UInt4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
|
||||
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
BOOL search_from_pos = FALSE;
|
||||
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
||||
|
||||
if (ci->disallow_premature)
|
||||
prepare_dummy_cursor = stmt->pre_executing;
|
||||
|
||||
@ -1320,25 +1362,15 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
*/
|
||||
else if (oldchar == '{')
|
||||
{
|
||||
char *esc;
|
||||
char *begin = &old_statement[opos + 1];
|
||||
char *begin = &old_statement[opos], *end;
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
char *end = multibyte_strchr(begin, '}');
|
||||
|
||||
#else
|
||||
char *end = strchr(begin, '}');
|
||||
#endif
|
||||
|
||||
if (!end)
|
||||
continue;
|
||||
/* procedure calls */
|
||||
if (stmt->statement_type == STMT_TYPE_PROCCALL)
|
||||
{
|
||||
int lit_call_len = 4;
|
||||
int lit_call_len = 4;
|
||||
|
||||
while (isspace((unsigned char) old_statement[++opos]));
|
||||
/* '=?' to accept return values exists ? */
|
||||
/* '?=' to accept return values exists ? */
|
||||
if (old_statement[opos] == '?')
|
||||
{
|
||||
param_number++;
|
||||
@ -1358,28 +1390,18 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
}
|
||||
opos += lit_call_len;
|
||||
CVT_APPEND_STR("SELECT ");
|
||||
#ifdef MULTIBYTE
|
||||
if (multibyte_strchr(&old_statement[opos], '('))
|
||||
#else
|
||||
if (strchr(&old_statement[opos], '('))
|
||||
#endif /* MULTIBYTE */
|
||||
if (my_strchr(&old_statement[opos], '('))
|
||||
proc_no_param = FALSE;
|
||||
continue;
|
||||
}
|
||||
*end = '\0';
|
||||
|
||||
esc = convert_escape(begin);
|
||||
if (esc)
|
||||
CVT_APPEND_STR(esc);
|
||||
else
|
||||
{ /* it's not a valid literal so just copy */
|
||||
*end = '}';
|
||||
CVT_APPEND_CHAR(oldchar);
|
||||
continue;
|
||||
if (convert_escape(begin, stmt, &npos, &new_stsize, &end) != CONVERT_ESCAPE_OK)
|
||||
{
|
||||
stmt->errormsg = "ODBC escape convert error";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
opos += end - begin + 1;
|
||||
*end = '}';
|
||||
opos = end - old_statement; /* positioned at the last } */
|
||||
new_statement = stmt->stmt_with_params;
|
||||
continue;
|
||||
}
|
||||
/* End of a procedure call */
|
||||
@ -1500,11 +1522,30 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt4 bind_size = stmt->options.param_bind_type;
|
||||
UInt4 ctypelen;
|
||||
|
||||
|
||||
used = stmt->parameters[param_number].used ? *stmt->parameters[param_number].used : SQL_NTS;
|
||||
|
||||
buffer = stmt->parameters[param_number].buffer;
|
||||
buffer = stmt->parameters[param_number].buffer + offset;
|
||||
if (current_row > 0)
|
||||
{
|
||||
if (bind_size > 0)
|
||||
buffer += (bind_size * current_row);
|
||||
else if (ctypelen = ctype_length(stmt->parameters[param_number].CType), ctypelen > 0)
|
||||
buffer += current_row * ctypelen;
|
||||
else
|
||||
buffer += current_row * stmt->parameters[param_number].buflen;
|
||||
}
|
||||
if (stmt->parameters[param_number].used)
|
||||
{
|
||||
UInt4 p_offset = offset;
|
||||
if (bind_size > 0)
|
||||
p_offset = offset + bind_size * current_row;
|
||||
else
|
||||
p_offset = offset + sizeof(SDWORD) * current_row;
|
||||
used = *(SDWORD *)((char *)stmt->parameters[param_number].used + p_offset);
|
||||
}
|
||||
else
|
||||
used = SQL_NTS;
|
||||
}
|
||||
|
||||
/* Handle NULL parameter data */
|
||||
@ -1570,6 +1611,20 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
*((SDWORD *) buffer));
|
||||
break;
|
||||
|
||||
#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
|
||||
#ifdef WIN32
|
||||
case SQL_C_SBIGINT:
|
||||
sprintf(param_string, "%I64d",
|
||||
*((SQLBIGINT *) buffer));
|
||||
break;
|
||||
|
||||
case SQL_C_UBIGINT:
|
||||
sprintf(param_string, "%I64u",
|
||||
*((SQLUBIGINT *) buffer));
|
||||
break;
|
||||
|
||||
#endif /* WIN32 */
|
||||
#endif /* ODBCINT64 */
|
||||
case SQL_C_SSHORT:
|
||||
case SQL_C_SHORT:
|
||||
sprintf(param_string, "%d",
|
||||
@ -1706,7 +1761,7 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
parse_datetime(cbuf, &st);
|
||||
}
|
||||
|
||||
sprintf(tmp, "'%.4d-%.2d-%.2d'", st.y, st.m, st.d);
|
||||
sprintf(tmp, "'%.4d-%.2d-%.2d'::date", st.y, st.m, st.d);
|
||||
|
||||
CVT_APPEND_STR(tmp);
|
||||
break;
|
||||
@ -1721,7 +1776,7 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
parse_datetime(cbuf, &st);
|
||||
}
|
||||
|
||||
sprintf(tmp, "'%.2d:%.2d:%.2d'", st.hh, st.mm, st.ss);
|
||||
sprintf(tmp, "'%.2d:%.2d:%.2d'::time", st.hh, st.mm, st.ss);
|
||||
|
||||
CVT_APPEND_STR(tmp);
|
||||
break;
|
||||
@ -1743,7 +1798,7 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
*/
|
||||
tmp[0] = '\'';
|
||||
/* Time zone stuff is unreliable */
|
||||
stime2timestamp(&st, tmp + 1, FALSE, PG_VERSION_GE(conn, 7.2));
|
||||
stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2));
|
||||
strcat(tmp, "'");
|
||||
|
||||
CVT_APPEND_STR(tmp);
|
||||
@ -1772,28 +1827,13 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
/* begin transaction if needed */
|
||||
if (!CC_is_in_trans(conn))
|
||||
{
|
||||
QResultClass *res;
|
||||
char ok;
|
||||
|
||||
res = CC_send_query(conn, "BEGIN", NULL);
|
||||
if (!res)
|
||||
if (!CC_begin(conn))
|
||||
{
|
||||
stmt->errormsg = "Could not begin (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
ok = QR_command_successful(res);
|
||||
QR_Destructor(res);
|
||||
if (!ok)
|
||||
{
|
||||
stmt->errormsg = "Could not begin (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
CC_set_in_trans(conn);
|
||||
}
|
||||
|
||||
/* store the oid */
|
||||
@ -1823,28 +1863,13 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
/* commit transaction if needed */
|
||||
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
|
||||
{
|
||||
QResultClass *res;
|
||||
char ok;
|
||||
|
||||
res = CC_send_query(conn, "COMMIT", NULL);
|
||||
if (!res)
|
||||
if (!CC_commit(conn))
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
ok = QR_command_successful(res);
|
||||
QR_Destructor(res);
|
||||
if (!ok)
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
CC_set_no_trans(conn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1951,49 +1976,95 @@ copy_statement_with_parameters(StatementClass *stmt)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
mapFunction(const char *func)
|
||||
static const char *
|
||||
mapFunction(const char *func, int param_count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mapFuncs[i][0]; i++)
|
||||
if (!stricmp(mapFuncs[i][0], func))
|
||||
{
|
||||
if (mapFuncs[i][0][0] == '%')
|
||||
{
|
||||
if (mapFuncs[i][0][1] - '0' == param_count &&
|
||||
!stricmp(mapFuncs[i][0] + 2, func))
|
||||
return mapFuncs[i][1];
|
||||
}
|
||||
else if (!stricmp(mapFuncs[i][0], func))
|
||||
return mapFuncs[i][1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int inner_convert_escape(const ConnectionClass *conn, const char *value, char *result, UInt4 maxLen, const char **input_resume, UInt4 *count);
|
||||
static int processParameters(const ConnectionClass *conn, const char *value, char *result, UInt4 maxLen, UInt4 *input_consumed, UInt4 *count, Int4 param_pos[][2]);
|
||||
|
||||
/*
|
||||
* convert_escape()
|
||||
*
|
||||
* This function returns a pointer to static memory!
|
||||
* inner_convert_escape()
|
||||
* work with embedded escapes sequences
|
||||
*/
|
||||
char *
|
||||
convert_escape(char *value)
|
||||
|
||||
static
|
||||
int inner_convert_escape(const ConnectionClass *conn, const char *value,
|
||||
char *result, UInt4 maxLen, const char **input_resume,
|
||||
UInt4 *count)
|
||||
{
|
||||
static char escape[1024];
|
||||
char key[33];
|
||||
|
||||
static const char *func = "inner_convert_escape";
|
||||
int subret, param_count;
|
||||
char valnts[1024], params[1024];
|
||||
char key[33], *end;
|
||||
const char *valptr;
|
||||
UInt4 vlen, prtlen, input_consumed, param_consumed;
|
||||
Int4 param_pos[16][2];
|
||||
|
||||
valptr = value;
|
||||
if (*valptr == '{') /* skip the first { */
|
||||
valptr++;
|
||||
/* Separate off the key, skipping leading and trailing whitespace */
|
||||
while ((*value != '\0') && isspace((unsigned char) *value))
|
||||
value++;
|
||||
sscanf(value, "%32s", key);
|
||||
while ((*value != '\0') && (!isspace((unsigned char) *value)))
|
||||
value++;
|
||||
while ((*value != '\0') && isspace((unsigned char) *value))
|
||||
value++;
|
||||
|
||||
mylog("convert_escape: key='%s', val='%s'\n", key, value);
|
||||
|
||||
if ((strcmp(key, "d") == 0) ||
|
||||
(strcmp(key, "t") == 0) ||
|
||||
(strcmp(key, "oj") == 0) || /* {oj syntax support for 7.1
|
||||
* servers */
|
||||
(strcmp(key, "ts") == 0))
|
||||
while ((*valptr != '\0') && isspace((unsigned char) *valptr))
|
||||
valptr++;
|
||||
sscanf(valptr, "%32s", key);
|
||||
while ((*valptr != '\0') && (!isspace((unsigned char) *valptr)))
|
||||
valptr++;
|
||||
while ((*valptr != '\0') && isspace((unsigned char) *valptr))
|
||||
valptr++;
|
||||
|
||||
if (end = my_strchr(valptr, '}'), NULL == end)
|
||||
{
|
||||
mylog("%s couldn't find the ending }\n",func);
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
}
|
||||
if (vlen = (UInt4)(end - valptr), maxLen <= vlen)
|
||||
return CONVERT_ESCAPE_OVERFLOW;
|
||||
memcpy(valnts, valptr, vlen);
|
||||
valnts[vlen] = '\0';
|
||||
*input_resume = valptr + vlen; /* resume from the last } */
|
||||
mylog("%s: key='%s', val='%s'\n", func, key, valnts);
|
||||
|
||||
if (strcmp(key, "d") == 0)
|
||||
{
|
||||
/* Literal; return the escape part adding type cast */
|
||||
prtlen = snprintf(result, maxLen, "%s::date", valnts);
|
||||
}
|
||||
else if (strcmp(key, "t") == 0)
|
||||
{
|
||||
/* Literal; return the escape part adding type cast */
|
||||
prtlen = snprintf(result, maxLen, "%s::time", valnts);
|
||||
}
|
||||
else if (strcmp(key, "ts") == 0)
|
||||
{
|
||||
/* Literal; return the escape part adding type cast */
|
||||
if (PG_VERSION_LT(conn, 7.1))
|
||||
prtlen = snprintf(result, maxLen, "%s::datetime", valnts);
|
||||
else
|
||||
prtlen = snprintf(result, maxLen, "%s::timestamp", valnts);
|
||||
}
|
||||
else if (strcmp(key, "oj") == 0) /* {oj syntax support for 7.1 * servers */
|
||||
{
|
||||
/* Literal; return the escape part as-is */
|
||||
strncpy(escape, value, sizeof(escape) - 1);
|
||||
strncpy(result, valnts, maxLen);
|
||||
prtlen = vlen;
|
||||
}
|
||||
else if (strcmp(key, "fn") == 0)
|
||||
{
|
||||
@ -2001,52 +2072,286 @@ convert_escape(char *value)
|
||||
* Function invocation Separate off the func name, skipping
|
||||
* trailing whitespace.
|
||||
*/
|
||||
char *funcEnd = value;
|
||||
char svchar;
|
||||
char *mapFunc;
|
||||
char *funcEnd = valnts;
|
||||
char svchar;
|
||||
const char *mapExpr;
|
||||
|
||||
params[sizeof(params)-1] = '\0';
|
||||
|
||||
while ((*funcEnd != '\0') && (*funcEnd != '(') &&
|
||||
(!isspace((unsigned char) *funcEnd)))
|
||||
(!isspace((unsigned char) *funcEnd)))
|
||||
funcEnd++;
|
||||
svchar = *funcEnd;
|
||||
*funcEnd = '\0';
|
||||
sscanf(value, "%32s", key);
|
||||
sscanf(valnts, "%32s", key);
|
||||
*funcEnd = svchar;
|
||||
while ((*funcEnd != '\0') && isspace((unsigned char) *funcEnd))
|
||||
funcEnd++;
|
||||
|
||||
/*
|
||||
* We expect left parenthesis here, else return fn body as-is
|
||||
* We expect left parenthesis here, else return fn body as-is
|
||||
* since it is one of those "function constants".
|
||||
*/
|
||||
if (*funcEnd != '(')
|
||||
{
|
||||
strncpy(escape, value, sizeof(escape) - 1);
|
||||
return escape;
|
||||
strncpy(result, valnts, maxLen);
|
||||
return CONVERT_ESCAPE_OK;
|
||||
}
|
||||
mapFunc = mapFunction(key);
|
||||
|
||||
/*
|
||||
* We could have mapFunction() return key if not in table... -
|
||||
* thomas 2000-04-03
|
||||
* Process parameter list and inner escape
|
||||
* sequences
|
||||
* Aceto 2002-01-29
|
||||
*/
|
||||
if (mapFunc == NULL)
|
||||
|
||||
valptr += (UInt4)(funcEnd - valnts);
|
||||
if (subret = processParameters(conn, valptr, params, sizeof(params) - 1, &input_consumed, ¶m_consumed, param_pos), CONVERT_ESCAPE_OK != subret)
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
|
||||
for (param_count = 0;; param_count++)
|
||||
{
|
||||
/* If unrecognized function name, return fn body as-is */
|
||||
strncpy(escape, value, sizeof(escape) - 1);
|
||||
return escape;
|
||||
if (param_pos[param_count][0] < 0)
|
||||
break;
|
||||
}
|
||||
/* copy mapped name and remaining input string */
|
||||
strcpy(escape, mapFunc);
|
||||
strncat(escape, funcEnd, sizeof(escape) - 1 - strlen(mapFunc));
|
||||
if (param_count == 1 &&
|
||||
param_pos[0][1] < param_pos[0][0])
|
||||
param_count = 0;
|
||||
|
||||
mapExpr = mapFunction(key, param_count);
|
||||
if (mapExpr == NULL)
|
||||
prtlen = snprintf(result, maxLen, "%s%s", key, params);
|
||||
else
|
||||
{
|
||||
const char *mapptr;
|
||||
int from, to, pidx, paramlen;
|
||||
|
||||
for (prtlen = 0, mapptr = mapExpr; *mapptr; mapptr++)
|
||||
{
|
||||
if (prtlen + 1 >= maxLen) /* buffer overflow */
|
||||
{
|
||||
result[prtlen] = '\0';
|
||||
prtlen++;
|
||||
break;
|
||||
}
|
||||
if (*mapptr != '$')
|
||||
{
|
||||
result[prtlen++] = *mapptr;
|
||||
continue;
|
||||
}
|
||||
mapptr++;
|
||||
if (*mapptr == '*')
|
||||
{
|
||||
from = 1;
|
||||
to = param_consumed - 2;
|
||||
}
|
||||
else if (isdigit(*mapptr))
|
||||
{
|
||||
pidx = *mapptr - '0' - 1;
|
||||
if (pidx < 0 ||
|
||||
param_pos[pidx][0] <0)
|
||||
{
|
||||
qlog("%s %dth param not found for the expression %s\n", pidx + 1, mapExpr);
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
}
|
||||
from = param_pos[pidx][0];
|
||||
to = param_pos[pidx][1];
|
||||
}
|
||||
else
|
||||
{
|
||||
qlog("%s internal expression error %s\n", func, mapExpr);
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
}
|
||||
paramlen = to - from + 1;
|
||||
if (prtlen + paramlen >= maxLen) /* buffer overflow */
|
||||
{
|
||||
prtlen = maxLen;
|
||||
break;
|
||||
}
|
||||
if (paramlen > 0)
|
||||
memcpy(&result[prtlen], params + from, paramlen);
|
||||
prtlen += paramlen;
|
||||
}
|
||||
if (prtlen < maxLen)
|
||||
result[prtlen] = '\0';
|
||||
/** prtlen = snprintf(result, maxLen, "%s%s", mapExpr, params); **/
|
||||
}
|
||||
valptr += input_consumed;
|
||||
*input_resume = valptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Bogus key, leave untranslated */
|
||||
return NULL;
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
}
|
||||
|
||||
if (count)
|
||||
*count = prtlen;
|
||||
if (prtlen < 0 || prtlen >= maxLen) /* buffer overflow */
|
||||
{
|
||||
mylog("%s %d bytes buffer overflow\n", func, maxLen);
|
||||
return CONVERT_ESCAPE_OVERFLOW;
|
||||
}
|
||||
return CONVERT_ESCAPE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* processParameters()
|
||||
* Process function parameters and work with embedded escapes sequences.
|
||||
*/
|
||||
|
||||
static
|
||||
int processParameters(const ConnectionClass *conn, const char *value,
|
||||
char *result, UInt4 maxLen, UInt4 *input_consumed,
|
||||
UInt4 *output_count, Int4 param_pos[][2])
|
||||
{
|
||||
int innerParenthesis, subret, param_count;
|
||||
UInt4 ipos, count, inner_count;
|
||||
unsigned char stop;
|
||||
const char *valptr;
|
||||
char buf[1024];
|
||||
BOOL in_quote, in_dquote, in_escape, leadingSpace;
|
||||
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
innerParenthesis = 0;
|
||||
in_quote = in_dquote = in_escape = leadingSpace = FALSE;
|
||||
param_count = 0;
|
||||
#ifdef MULTIBYTE
|
||||
multibyte_init();
|
||||
#endif /* MULTIBYTE */
|
||||
/* begin with outer '(' */
|
||||
for (stop = FALSE, valptr = value, ipos = count = 0; *valptr != '\0'; ipos++, valptr++)
|
||||
{
|
||||
if (leadingSpace)
|
||||
{
|
||||
if (isspace(*valptr))
|
||||
continue;
|
||||
leadingSpace = FALSE;
|
||||
}
|
||||
if (count + 1 >= maxLen) /* buffer overflow */
|
||||
{
|
||||
*input_consumed = 0;
|
||||
result[count++] = '\0';
|
||||
return CONVERT_ESCAPE_OVERFLOW;
|
||||
}
|
||||
#ifdef MULTIBYTE
|
||||
if (multibyte_char_check(*valptr) != 0)
|
||||
{
|
||||
result[count++] = *valptr;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* From here we are guaranteed to handle a 1-byte character.
|
||||
*/
|
||||
#endif
|
||||
if (in_quote)
|
||||
{
|
||||
if (in_escape)
|
||||
in_escape = FALSE;
|
||||
else if (*valptr == '\\')
|
||||
in_escape = TRUE;
|
||||
else if (*valptr == '\'')
|
||||
in_quote = FALSE;
|
||||
result[count++] = *valptr;
|
||||
continue;
|
||||
}
|
||||
else if (in_dquote)
|
||||
{
|
||||
if (*valptr == '\"')
|
||||
in_dquote = FALSE;
|
||||
result[count++] = *valptr;
|
||||
continue;
|
||||
}
|
||||
switch (*valptr)
|
||||
{
|
||||
case '\'':
|
||||
in_quote = TRUE;
|
||||
break;
|
||||
case '\"':
|
||||
in_dquote = TRUE;
|
||||
break;
|
||||
case ',':
|
||||
if (1 == innerParenthesis)
|
||||
{
|
||||
param_pos[param_count][1] = count - 1;
|
||||
param_count++;
|
||||
param_pos[param_count][0] = count + 1;
|
||||
param_pos[param_count][1] = -1;
|
||||
leadingSpace = TRUE;
|
||||
}
|
||||
break;
|
||||
case '(':
|
||||
if (0 == innerParenthesis)
|
||||
{
|
||||
param_pos[param_count][0] = count + 1;
|
||||
param_pos[param_count][1] = -1;
|
||||
leadingSpace = TRUE;
|
||||
}
|
||||
innerParenthesis++;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
innerParenthesis--;
|
||||
if (0 == innerParenthesis)
|
||||
{
|
||||
param_pos[param_count][1] = count - 1;
|
||||
param_count++;
|
||||
param_pos[param_count][0] =
|
||||
param_pos[param_count][1] = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '}':
|
||||
stop = TRUE;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
if (subret = inner_convert_escape(conn, valptr, buf, sizeof(buf) - 1, &valptr, &inner_count), CONVERT_ESCAPE_OK != subret)
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
|
||||
if (inner_count + count >= maxLen)
|
||||
return CONVERT_ESCAPE_OVERFLOW;
|
||||
memcpy(&result[count], buf, inner_count);
|
||||
count += inner_count;
|
||||
ipos = (UInt4) (valptr - value);
|
||||
continue;
|
||||
}
|
||||
if (stop) /* returns with the last } position */
|
||||
break;
|
||||
result[count++] = *valptr;
|
||||
}
|
||||
if (param_pos[param_count][0] >= 0)
|
||||
{
|
||||
mylog("processParameters closing ) not found %d\n", innerParenthesis);
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
}
|
||||
result[count] = '\0';
|
||||
*input_consumed = ipos;
|
||||
if (output_count)
|
||||
*output_count = count;
|
||||
return CONVERT_ESCAPE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert_escape()
|
||||
* This function returns a pointer to static memory!
|
||||
*/
|
||||
|
||||
int
|
||||
convert_escape(const char *value, StatementClass *stmt, int *npos, int *stsize, const char **val_resume)
|
||||
{
|
||||
int ret, pos = *npos;
|
||||
UInt4 count;
|
||||
|
||||
return escape;
|
||||
while (ret = inner_convert_escape(SC_get_conn(stmt), value,
|
||||
stmt->stmt_with_params + pos, *stsize - pos, val_resume, &count),
|
||||
CONVERT_ESCAPE_OVERFLOW == ret)
|
||||
{
|
||||
if ((*stsize = enlarge_statement(stmt, *stsize * 2)) <= 0)
|
||||
return CONVERT_ESCAPE_ERROR;
|
||||
}
|
||||
if (CONVERT_ESCAPE_OK == ret)
|
||||
*npos += count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -2218,7 +2523,7 @@ convert_special_chars(const char *si, char *dst, int used)
|
||||
multibyte_init();
|
||||
#endif
|
||||
|
||||
for (i = 0; i < max; i++)
|
||||
for (i = 0; i < max && si[i]; i++)
|
||||
{
|
||||
#ifdef MULTIBYTE
|
||||
if (multibyte_char_check(si[i]) != 0)
|
||||
@ -2514,26 +2819,12 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
|
||||
/* begin transaction if needed */
|
||||
if (!CC_is_in_trans(conn))
|
||||
{
|
||||
QResultClass *res;
|
||||
char ok;
|
||||
|
||||
res = CC_send_query(conn, "BEGIN", NULL);
|
||||
if (!res)
|
||||
if (!CC_begin(conn))
|
||||
{
|
||||
stmt->errormsg = "Could not begin (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
return COPY_GENERAL_ERROR;
|
||||
}
|
||||
ok = QR_command_successful(res);
|
||||
QR_Destructor(res);
|
||||
if (!ok)
|
||||
{
|
||||
stmt->errormsg = "Could not begin (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
return COPY_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
CC_set_in_trans(conn);
|
||||
}
|
||||
|
||||
oid = atoi(value);
|
||||
@ -2577,26 +2868,12 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
|
||||
/* commit transaction if needed */
|
||||
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
|
||||
{
|
||||
QResultClass *res;
|
||||
char ok;
|
||||
|
||||
res = CC_send_query(conn, "COMMIT", NULL);
|
||||
if (!res)
|
||||
if (!CC_commit(conn))
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
return COPY_GENERAL_ERROR;
|
||||
}
|
||||
ok = QR_command_successful(res);
|
||||
QR_Destructor(res);
|
||||
if (!ok)
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
return COPY_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
CC_set_no_trans(conn);
|
||||
}
|
||||
|
||||
stmt->lobj_fd = -1;
|
||||
@ -2626,26 +2903,12 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
|
||||
/* commit transaction if needed */
|
||||
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
|
||||
{
|
||||
QResultClass *res;
|
||||
char ok;
|
||||
|
||||
res = CC_send_query(conn, "COMMIT", NULL);
|
||||
if (!res)
|
||||
if (!CC_commit(conn))
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
return COPY_GENERAL_ERROR;
|
||||
}
|
||||
ok = QR_command_successful(res);
|
||||
QR_Destructor(res);
|
||||
if (!ok)
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
return COPY_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
CC_set_no_trans(conn);
|
||||
}
|
||||
|
||||
stmt->lobj_fd = -1; /* prevent further reading */
|
||||
|
@ -18,6 +18,10 @@
|
||||
#define COPY_RESULT_TRUNCATED 3
|
||||
#define COPY_GENERAL_ERROR 4
|
||||
#define COPY_NO_DATA_FOUND 5
|
||||
/* convert_escape results */
|
||||
#define CONVERT_ESCAPE_OK 0
|
||||
#define CONVERT_ESCAPE_OVERFLOW 1
|
||||
#define CONVERT_ESCAPE_ERROR 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -35,7 +39,8 @@ int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, I
|
||||
PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue);
|
||||
|
||||
int copy_statement_with_parameters(StatementClass *stmt);
|
||||
char *convert_escape(char *value);
|
||||
int convert_escape(const char *value, StatementClass *stmt,
|
||||
int *npos, int *stsize, const char **val_resume);
|
||||
BOOL convert_money(const char *s, char *sout, size_t soutmax);
|
||||
char parse_datetime(char *buf, SIMPLE_TIME *st);
|
||||
int convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed);
|
||||
|
@ -233,6 +233,9 @@ PGAPI_Error(
|
||||
case STMT_INVALID_CURSOR_POSITION:
|
||||
strcpy(szSqlState, "S1109");
|
||||
break;
|
||||
case STMT_RETURN_NULL_WITHOUT_INDICATOR:
|
||||
strcpy(szSqlState, "22002");
|
||||
break;
|
||||
case STMT_VALUE_OUT_OF_RANGE:
|
||||
strcpy(szSqlState, "22003");
|
||||
break;
|
||||
@ -376,6 +379,9 @@ PGAPI_Error(
|
||||
case STMT_NOT_IMPLEMENTED_ERROR:
|
||||
strcpy(szSqlState, "S1C00");
|
||||
break;
|
||||
case STMT_RETURN_NULL_WITHOUT_INDICATOR:
|
||||
strcpy(szSqlState, "22002");
|
||||
break;
|
||||
case CONN_VALUE_OUT_OF_RANGE:
|
||||
case STMT_VALUE_OUT_OF_RANGE:
|
||||
strcpy(szSqlState, "22003");
|
||||
|
@ -196,7 +196,7 @@ PGAPI_Execute(
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
ConnectionClass *conn;
|
||||
int i,
|
||||
retval;
|
||||
retval, start_row, end_row;
|
||||
|
||||
mylog("%s: entering...\n", func);
|
||||
|
||||
@ -215,7 +215,10 @@ PGAPI_Execute(
|
||||
if (stmt->prepare && stmt->status == STMT_PREMATURE)
|
||||
{
|
||||
if (stmt->inaccurate_result)
|
||||
{
|
||||
stmt->exec_current_row = -1;
|
||||
SC_recycle_statement(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt->status = STMT_FINISHED;
|
||||
@ -278,6 +281,35 @@ PGAPI_Execute(
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (start_row = stmt->exec_start_row, start_row < 0)
|
||||
start_row = 0;
|
||||
if (end_row = stmt->exec_end_row, end_row < 0)
|
||||
end_row = stmt->options.paramset_size - 1;
|
||||
if (stmt->exec_current_row < 0)
|
||||
stmt->exec_current_row = start_row;
|
||||
if (stmt->exec_current_row == start_row)
|
||||
{
|
||||
if (stmt->options.param_processed_ptr)
|
||||
*stmt->options.param_processed_ptr = 0;
|
||||
}
|
||||
|
||||
next_param_row:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
if (stmt->options.param_operation_ptr)
|
||||
{
|
||||
while (stmt->options.param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
|
||||
{
|
||||
if (stmt->options.param_status_ptr)
|
||||
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_UNUSED;
|
||||
if (stmt->exec_current_row >= end_row)
|
||||
{
|
||||
stmt->exec_current_row = -1;
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
++stmt->exec_current_row;
|
||||
}
|
||||
}
|
||||
#endif /* ODBCVER */
|
||||
/*
|
||||
* Check if statement has any data-at-execute parameters when it is
|
||||
* not in SC_pre_execute.
|
||||
@ -289,17 +321,27 @@ PGAPI_Execute(
|
||||
* execute of this statement? Therefore check for params and
|
||||
* re-copy.
|
||||
*/
|
||||
UInt4 offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0;
|
||||
Int4 bind_size = stmt->options.param_bind_type;
|
||||
Int4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
|
||||
|
||||
stmt->data_at_exec = -1;
|
||||
for (i = 0; i < stmt->parameters_allocated; i++)
|
||||
{
|
||||
Int4 *pcVal = stmt->parameters[i].used;
|
||||
|
||||
if (pcVal && (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET))
|
||||
stmt->parameters[i].data_at_exec = TRUE;
|
||||
else
|
||||
stmt->parameters[i].data_at_exec = FALSE;
|
||||
stmt->parameters[i].data_at_exec = FALSE;
|
||||
if (pcVal)
|
||||
{
|
||||
if (bind_size > 0)
|
||||
pcVal = (Int4 *)((char *)pcVal + offset + bind_size * current_row);
|
||||
else
|
||||
pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
|
||||
if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)
|
||||
stmt->parameters[i].data_at_exec = TRUE;
|
||||
}
|
||||
/* Check for data at execution parameters */
|
||||
if (stmt->parameters[i].data_at_exec == TRUE)
|
||||
if (stmt->parameters[i].data_at_exec)
|
||||
{
|
||||
if (stmt->data_at_exec < 0)
|
||||
stmt->data_at_exec = 1;
|
||||
@ -333,68 +375,88 @@ PGAPI_Execute(
|
||||
|
||||
mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params);
|
||||
|
||||
if (!stmt->inaccurate_result || !conn->connInfo.disallow_premature)
|
||||
{
|
||||
retval = SC_execute(stmt);
|
||||
if (retval != SQL_ERROR)
|
||||
{
|
||||
if (stmt->options.param_processed_ptr)
|
||||
(*stmt->options.param_processed_ptr)++;
|
||||
}
|
||||
#if (ODBCVER >= 0x0300)
|
||||
if (stmt->options.param_status_ptr)
|
||||
{
|
||||
switch (retval)
|
||||
{
|
||||
case SQL_SUCCESS:
|
||||
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
|
||||
break;
|
||||
case SQL_SUCCESS_WITH_INFO:
|
||||
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
|
||||
break;
|
||||
default:
|
||||
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* ODBCVER */
|
||||
if (retval == SQL_ERROR ||
|
||||
stmt->inaccurate_result ||
|
||||
stmt->exec_current_row >= end_row)
|
||||
{
|
||||
stmt->exec_current_row = -1;
|
||||
return retval;
|
||||
}
|
||||
stmt->exec_current_row++;
|
||||
goto next_param_row;
|
||||
}
|
||||
/*
|
||||
* Get the field info for the prepared query using dummy backward
|
||||
* fetch.
|
||||
*/
|
||||
if (stmt->inaccurate_result && conn->connInfo.disallow_premature)
|
||||
if (SC_is_pre_executable(stmt))
|
||||
{
|
||||
if (SC_is_pre_executable(stmt))
|
||||
{
|
||||
BOOL in_trans = CC_is_in_trans(conn);
|
||||
BOOL issued_begin = FALSE,
|
||||
begin_included = FALSE;
|
||||
QResultClass *res;
|
||||
BOOL in_trans = CC_is_in_trans(conn);
|
||||
BOOL issued_begin = FALSE,
|
||||
begin_included = FALSE;
|
||||
QResultClass *res;
|
||||
|
||||
if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
|
||||
begin_included = TRUE;
|
||||
else if (!in_trans)
|
||||
if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
|
||||
begin_included = TRUE;
|
||||
else if (!in_trans)
|
||||
{
|
||||
if (issued_begin = CC_begin(conn), !issued_begin)
|
||||
{
|
||||
res = CC_send_query(conn, "BEGIN", NULL);
|
||||
if (res && !QR_aborted(res))
|
||||
issued_begin = TRUE;
|
||||
if (res)
|
||||
QR_Destructor(res);
|
||||
if (!issued_begin)
|
||||
{
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
stmt->errormsg = "Handle prepare error";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
}
|
||||
/* we are now in a transaction */
|
||||
CC_set_in_trans(conn);
|
||||
stmt->result = res = CC_send_query(conn, stmt->stmt_with_params, NULL);
|
||||
if (!res || QR_aborted(res))
|
||||
{
|
||||
CC_abort(conn);
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
stmt->errormsg = "Handle prepare error";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CC_is_in_autocommit(conn))
|
||||
{
|
||||
if (issued_begin)
|
||||
{
|
||||
res = CC_send_query(conn, "COMMIT", NULL);
|
||||
CC_set_no_trans(conn);
|
||||
if (res)
|
||||
QR_Destructor(res);
|
||||
}
|
||||
else if (!in_trans && begin_included)
|
||||
CC_set_no_trans(conn);
|
||||
}
|
||||
stmt->status = STMT_FINISHED;
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
}
|
||||
/* we are now in a transaction */
|
||||
CC_set_in_trans(conn);
|
||||
stmt->result = res = CC_send_query(conn, stmt->stmt_with_params, NULL);
|
||||
if (!res || QR_aborted(res))
|
||||
{
|
||||
CC_abort(conn);
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
stmt->errormsg = "Handle prepare error";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CC_is_in_autocommit(conn))
|
||||
{
|
||||
if (issued_begin)
|
||||
CC_commit(conn);
|
||||
else if (!in_trans && begin_included)
|
||||
CC_set_no_trans(conn);
|
||||
}
|
||||
stmt->status = STMT_FINISHED;
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return SC_execute(stmt);
|
||||
else
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -659,21 +721,7 @@ PGAPI_ParamData(
|
||||
/* commit transaction if needed */
|
||||
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
|
||||
{
|
||||
QResultClass *res;
|
||||
char ok;
|
||||
|
||||
res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
|
||||
if (!res)
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
ok = QR_command_successful(res);
|
||||
CC_set_no_trans(stmt->hdbc);
|
||||
QR_Destructor(res);
|
||||
if (!ok)
|
||||
if (!CC_commit(stmt->hdbc))
|
||||
{
|
||||
stmt->errormsg = "Could not commit (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
@ -687,13 +735,47 @@ PGAPI_ParamData(
|
||||
/* Done, now copy the params and then execute the statement */
|
||||
if (stmt->data_at_exec == 0)
|
||||
{
|
||||
int end_row;
|
||||
|
||||
retval = copy_statement_with_parameters(stmt);
|
||||
if (retval != SQL_SUCCESS)
|
||||
return retval;
|
||||
|
||||
stmt->current_exec_param = -1;
|
||||
|
||||
return SC_execute(stmt);
|
||||
retval = SC_execute(stmt);
|
||||
if (retval != SQL_ERROR)
|
||||
{
|
||||
if (stmt->options.param_processed_ptr)
|
||||
(*stmt->options.param_processed_ptr)++;
|
||||
}
|
||||
#if (ODBCVER >= 0x0300)
|
||||
if (stmt->options.param_status_ptr)
|
||||
{
|
||||
switch (retval)
|
||||
{
|
||||
case SQL_SUCCESS:
|
||||
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
|
||||
break;
|
||||
case SQL_SUCCESS_WITH_INFO:
|
||||
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
|
||||
break;
|
||||
default:
|
||||
stmt->options.param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* ODBCVER */
|
||||
if (stmt->exec_end_row < 0)
|
||||
end_row = stmt->options.paramset_size - 1;
|
||||
if (retval == SQL_ERROR ||
|
||||
stmt->exec_current_row >= end_row)
|
||||
{
|
||||
stmt->exec_current_row = -1;
|
||||
return retval;
|
||||
}
|
||||
stmt->exec_current_row++;
|
||||
return PGAPI_Execute(stmt);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -705,7 +787,7 @@ PGAPI_ParamData(
|
||||
/* At least 1 data at execution parameter, so Fill in the token value */
|
||||
for (; i < stmt->parameters_allocated; i++)
|
||||
{
|
||||
if (stmt->parameters[i].data_at_exec == TRUE)
|
||||
if (stmt->parameters[i].data_at_exec)
|
||||
{
|
||||
stmt->data_at_exec--;
|
||||
stmt->current_exec_param = i;
|
||||
@ -780,28 +862,13 @@ PGAPI_PutData(
|
||||
/* begin transaction if needed */
|
||||
if (!CC_is_in_trans(stmt->hdbc))
|
||||
{
|
||||
QResultClass *res;
|
||||
char ok;
|
||||
|
||||
res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
|
||||
if (!res)
|
||||
if (!CC_begin(stmt->hdbc))
|
||||
{
|
||||
stmt->errormsg = "Could not begin (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
ok = QR_command_successful(res);
|
||||
QR_Destructor(res);
|
||||
if (!ok)
|
||||
{
|
||||
stmt->errormsg = "Could not begin (in-line) a transaction";
|
||||
stmt->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
CC_set_in_trans(stmt->hdbc);
|
||||
}
|
||||
|
||||
/* store the oid */
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include "misc.h"
|
||||
#include "pgtypes.h"
|
||||
#include "pgapifunc.h"
|
||||
#ifdef MULTIBYTE
|
||||
#include "multibyte.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* Trigger related stuff for SQLForeign Keys */
|
||||
@ -567,7 +570,10 @@ PGAPI_GetInfo(
|
||||
break;
|
||||
|
||||
case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
|
||||
p = "";
|
||||
if (PG_VERSION_GE(conn, 6.5))
|
||||
p = "\\";
|
||||
else
|
||||
p = "";
|
||||
break;
|
||||
|
||||
case SQL_SERVER_NAME: /* ODBC 1.0 */
|
||||
@ -1365,7 +1371,8 @@ PGAPI_Tables(
|
||||
{
|
||||
row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField));
|
||||
|
||||
set_tuplefield_string(&row->tuple[0], "");
|
||||
/*set_tuplefield_string(&row->tuple[0], "");*/
|
||||
set_tuplefield_null(&row->tuple[0]);
|
||||
|
||||
/*
|
||||
* I have to hide the table owner from Access, otherwise it
|
||||
@ -1378,7 +1385,8 @@ PGAPI_Tables(
|
||||
|
||||
mylog("%s: table_name = '%s'\n", func, table_name);
|
||||
|
||||
set_tuplefield_string(&row->tuple[1], "");
|
||||
/* set_tuplefield_string(&row->tuple[1], ""); */
|
||||
set_tuplefield_null(&row->tuple[1]);
|
||||
set_tuplefield_string(&row->tuple[2], table_name);
|
||||
set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
|
||||
set_tuplefield_string(&row->tuple[4], "");
|
||||
@ -1413,6 +1421,66 @@ PGAPI_Tables(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PostgreSQL needs 2 '\\' to escape '_' and '%'.
|
||||
*/
|
||||
static int
|
||||
reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len)
|
||||
{
|
||||
int i, outlen;
|
||||
const char *in;
|
||||
BOOL escape_in = FALSE;
|
||||
|
||||
if (srclen == SQL_NULL_DATA)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
return STRCPY_NULL;
|
||||
}
|
||||
else if (srclen == SQL_NTS)
|
||||
srclen = strlen(src);
|
||||
if (srclen <= 0)
|
||||
return STRCPY_FAIL;
|
||||
#ifdef MULTIBYTE
|
||||
multibyte_init();
|
||||
#endif
|
||||
for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++)
|
||||
{
|
||||
#ifdef MULTIBYTE
|
||||
if (multibyte_char_check(*in) != 0)
|
||||
{
|
||||
dest[outlen++] = *in;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (escape_in)
|
||||
{
|
||||
switch (*in)
|
||||
{
|
||||
case '%':
|
||||
case '_':
|
||||
dest[outlen++] = '\\'; /* needs 1 more */
|
||||
break;
|
||||
default:
|
||||
dest[outlen++] = '\\';
|
||||
if (outlen < dst_len)
|
||||
dest[outlen++] = '\\';
|
||||
if (outlen < dst_len)
|
||||
dest[outlen++] = '\\';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*in == '\\')
|
||||
escape_in = TRUE;
|
||||
else
|
||||
escape_in = FALSE;
|
||||
if (outlen < dst_len)
|
||||
dest[outlen++] = *in;
|
||||
}
|
||||
if (outlen < dst_len)
|
||||
dest[outlen] = '\0';
|
||||
return outlen;
|
||||
}
|
||||
|
||||
RETCODE SQL_API
|
||||
PGAPI_Columns(
|
||||
HSTMT hstmt,
|
||||
@ -1423,7 +1491,8 @@ PGAPI_Columns(
|
||||
UCHAR FAR * szTableName,
|
||||
SWORD cbTableName,
|
||||
UCHAR FAR * szColumnName,
|
||||
SWORD cbColumnName)
|
||||
SWORD cbColumnName,
|
||||
UWORD flag)
|
||||
{
|
||||
static char *func = "PGAPI_Columns";
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
@ -1476,9 +1545,22 @@ PGAPI_Columns(
|
||||
" and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
|
||||
PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
|
||||
|
||||
my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName);
|
||||
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
|
||||
my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
|
||||
if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
|
||||
{
|
||||
my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
|
||||
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
|
||||
my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName);
|
||||
}
|
||||
else
|
||||
{
|
||||
char esc_table_name[MAX_TABLE_LEN * 2];
|
||||
int escTbnamelen;
|
||||
|
||||
escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name));
|
||||
my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen);
|
||||
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
|
||||
my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
|
||||
}
|
||||
|
||||
/*
|
||||
* give the output in the order the columns were defined when the
|
||||
@ -1730,7 +1812,7 @@ PGAPI_Columns(
|
||||
*----------
|
||||
*/
|
||||
qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n",
|
||||
table_name, field_name, field_type, pgtype_to_sqltype, field_type_name);
|
||||
table_name, field_name, field_type, pgtype_to_sqltype(stmt,field_type), field_type_name);
|
||||
|
||||
useStaticPrecision = TRUE;
|
||||
|
||||
@ -1892,8 +1974,10 @@ PGAPI_SpecialColumns(
|
||||
"from pg_user u, pg_class c where "
|
||||
"u.usesysid = c.relowner");
|
||||
|
||||
my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName);
|
||||
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
|
||||
/* TableName cannot contain a string search pattern */
|
||||
my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
|
||||
/* SchemaName cannot contain a string search pattern */
|
||||
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
|
||||
|
||||
|
||||
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
|
||||
@ -2114,8 +2198,11 @@ PGAPI_Statistics(
|
||||
* being shown. This would throw everything off.
|
||||
*/
|
||||
col_stmt->internal = TRUE;
|
||||
/*
|
||||
* table_name parameter cannot contain a string search pattern.
|
||||
*/
|
||||
result = PGAPI_Columns(hcol_stmt, "", 0, "", 0,
|
||||
table_name, (SWORD) strlen(table_name), "", 0);
|
||||
table_name, (SWORD) strlen(table_name), "", 0, PODBC_NOT_SEARCH_PATTERN);
|
||||
col_stmt->internal = FALSE;
|
||||
|
||||
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
|
||||
@ -2725,9 +2812,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
|
||||
continueExec = (continueExec && !bError);
|
||||
if (bError && CC_is_in_trans(conn))
|
||||
{
|
||||
if (res = CC_send_query(conn, "abort", NULL), res)
|
||||
QR_Destructor(res);
|
||||
CC_set_no_trans(conn);
|
||||
CC_abort(conn);
|
||||
bError = FALSE;
|
||||
}
|
||||
/* restore the client encoding */
|
||||
@ -2811,9 +2896,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
|
||||
continueExec = (continueExec && !bError);
|
||||
if (bError && CC_is_in_trans(conn))
|
||||
{
|
||||
if (res = CC_send_query(conn, "abort", NULL), res)
|
||||
QR_Destructor(res);
|
||||
CC_set_no_trans(conn);
|
||||
CC_abort(conn);
|
||||
bError = FALSE;
|
||||
}
|
||||
/* restore the cleint encoding */
|
||||
@ -3647,7 +3730,7 @@ PGAPI_Procedures(
|
||||
" proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
|
||||
" '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
|
||||
" '' as " "REMARKS" ","
|
||||
" case when prorettype =0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
|
||||
" case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
|
||||
my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName);
|
||||
|
||||
res = CC_send_query(conn, proc_query, NULL);
|
||||
|
@ -84,8 +84,8 @@ SQLColumns(HSTMT StatementHandle,
|
||||
{
|
||||
mylog("[SQLColumns]");
|
||||
return PGAPI_Columns(StatementHandle, CatalogName, NameLength1,
|
||||
SchemaName, NameLength2, TableName, NameLength3,
|
||||
ColumnName, NameLength4);
|
||||
SchemaName, NameLength2, TableName, NameLength3,
|
||||
ColumnName, NameLength4, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -218,7 +218,7 @@ SQLFetch(HSTMT StatementHandle)
|
||||
RETCODE SQL_API
|
||||
SQLFreeConnect(HDBC ConnectionHandle)
|
||||
{
|
||||
mylog("[SQLFreeStmt]");
|
||||
mylog("[SQLFreeConnect]");
|
||||
return PGAPI_FreeConnect(ConnectionHandle);
|
||||
}
|
||||
|
||||
|
@ -85,12 +85,47 @@ SQLColAttribute(HSTMT StatementHandle,
|
||||
StringLength, NumericAttribute);
|
||||
}
|
||||
|
||||
static HSTMT
|
||||
descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
|
||||
{
|
||||
switch (descType)
|
||||
{
|
||||
case SQL_ATTR_APP_ROW_DESC: /* 10010 */
|
||||
return StatementHandle; /* this is bogus */
|
||||
case SQL_ATTR_APP_PARAM_DESC: /* 10011 */
|
||||
return (HSTMT) ((SQLUINTEGER) StatementHandle + 1) ; /* this is bogus */
|
||||
case SQL_ATTR_IMP_ROW_DESC: /* 10012 */
|
||||
return (HSTMT) ((SQLUINTEGER) StatementHandle + 2); /* this is bogus */
|
||||
case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */
|
||||
return (HSTMT) ((SQLUINTEGER) StatementHandle + 3); /* this is bogus */
|
||||
}
|
||||
return (HSTMT) 0;
|
||||
}
|
||||
static HSTMT
|
||||
statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType)
|
||||
{
|
||||
SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4;
|
||||
switch (res)
|
||||
{
|
||||
case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */
|
||||
break;
|
||||
case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */
|
||||
break;
|
||||
case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */
|
||||
break;
|
||||
case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */
|
||||
break;
|
||||
}
|
||||
return (HSTMT) ((SQLUINTEGER) DescHandle - res);
|
||||
}
|
||||
|
||||
/* new function */
|
||||
RETCODE SQL_API
|
||||
SQLCopyDesc(SQLHDESC SourceDescHandle,
|
||||
SQLHDESC TargetDescHandle)
|
||||
{
|
||||
mylog("[[SQLCopyDesc]]\n");
|
||||
mylog("Error not implemented\n");
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
@ -129,7 +164,10 @@ SQLFetchScroll(HSTMT StatementHandle,
|
||||
if (FetchOrientation == SQL_FETCH_BOOKMARK)
|
||||
{
|
||||
if (stmt->options.bookmark_ptr)
|
||||
{
|
||||
FetchOffset += *((Int4 *) stmt->options.bookmark_ptr);
|
||||
mylog("real FetchOffset = %d\n", FetchOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
@ -172,6 +210,7 @@ SQLGetDescField(SQLHDESC DescriptorHandle,
|
||||
SQLINTEGER *StringLength)
|
||||
{
|
||||
mylog("[[SQLGetDescField]]\n");
|
||||
mylog("Error not implemented\n");
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
@ -185,6 +224,7 @@ SQLGetDescRec(SQLHDESC DescriptorHandle,
|
||||
SQLSMALLINT *Scale, SQLSMALLINT *Nullable)
|
||||
{
|
||||
mylog("[[SQLGetDescRec]]\n");
|
||||
mylog("Error not implemented\n");
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
@ -305,22 +345,51 @@ SQLGetStmtAttr(HSTMT StatementHandle,
|
||||
RETCODE ret = SQL_SUCCESS;
|
||||
int len = 0;
|
||||
|
||||
mylog("[[%s]] %d\n", func, Attribute);
|
||||
mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
|
||||
switch (Attribute)
|
||||
{
|
||||
case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */
|
||||
Value = stmt->options.bookmark_ptr;
|
||||
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
|
||||
Value = stmt->options.param_offset_ptr;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
|
||||
*((SQLUINTEGER *) Value) = stmt->options.param_bind_type;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
|
||||
Value = stmt->options.param_operation_ptr;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
|
||||
Value = stmt->options.param_status_ptr;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
|
||||
Value = stmt->options.param_processed_ptr;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
|
||||
*((SQLUINTEGER *) Value) = stmt->options.paramset_size;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
|
||||
Value = stmt->options.row_offset_ptr;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
|
||||
Value = stmt->options.row_operation_ptr;
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_ROW_STATUS_PTR: /* 25 */
|
||||
Value = stmt->options.rowStatusArray;
|
||||
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
|
||||
Value = stmt->options.rowsFetched;
|
||||
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
|
||||
@ -328,30 +397,17 @@ SQLGetStmtAttr(HSTMT StatementHandle,
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_APP_ROW_DESC: /* 10010 */
|
||||
*((HSTMT *) Value) = StatementHandle; /* this is useless */
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_APP_PARAM_DESC: /* 10011 */
|
||||
*((HSTMT *) Value) = StatementHandle; /* this is useless */
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_IMP_ROW_DESC: /* 10012 */
|
||||
*((HSTMT *) Value) = StatementHandle; /* this is useless */
|
||||
len = 4;
|
||||
break;
|
||||
case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */
|
||||
*((HSTMT *) Value) = StatementHandle; /* this is useless */
|
||||
len = 4;
|
||||
*((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute);
|
||||
break;
|
||||
case SQL_ATTR_AUTO_IPD: /* 10001 */
|
||||
/* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
|
||||
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
|
||||
case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
|
||||
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
|
||||
|
||||
case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */
|
||||
case SQL_ATTR_CURSOR_SENSITIVITY: /* -2 */
|
||||
|
||||
case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */
|
||||
case SQL_ATTR_METADATA_ID: /* 10014 */
|
||||
|
||||
@ -359,11 +415,6 @@ SQLGetStmtAttr(HSTMT StatementHandle,
|
||||
* case SQL_ATTR_PREDICATE_PTR: case
|
||||
* SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
|
||||
*/
|
||||
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
|
||||
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
|
||||
case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
|
||||
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
|
||||
case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
|
||||
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
|
||||
stmt->errormsg = "Unsupported statement option (Get)";
|
||||
SC_log_error(func, "", stmt);
|
||||
@ -400,14 +451,127 @@ SQLSetConnectAttr(HDBC ConnectionHandle,
|
||||
return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
|
||||
}
|
||||
|
||||
static RETCODE SQL_API
|
||||
ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
|
||||
{
|
||||
RETCODE ret = SQL_SUCCESS;
|
||||
switch (FieldIdentifier)
|
||||
{
|
||||
case SQL_DESC_ARRAY_SIZE:
|
||||
stmt->options.rowset_size = (SQLUINTEGER) Value;
|
||||
break;
|
||||
case SQL_DESC_ARRAY_STATUS_PTR:
|
||||
stmt->options.row_operation_ptr = Value;
|
||||
break;
|
||||
case SQL_DESC_BIND_OFFSET_PTR:
|
||||
stmt->options.row_offset_ptr = Value;
|
||||
break;
|
||||
case SQL_DESC_BIND_TYPE:
|
||||
stmt->options.bind_size = (SQLUINTEGER) Value;
|
||||
break;
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RETCODE SQL_API
|
||||
APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
|
||||
{
|
||||
RETCODE ret = SQL_SUCCESS;
|
||||
switch (FieldIdentifier)
|
||||
{
|
||||
case SQL_DESC_ARRAY_SIZE:
|
||||
stmt->options.paramset_size = (SQLUINTEGER) Value;
|
||||
break;
|
||||
case SQL_DESC_ARRAY_STATUS_PTR:
|
||||
stmt->options.param_operation_ptr = Value;
|
||||
break;
|
||||
case SQL_DESC_BIND_OFFSET_PTR:
|
||||
stmt->options.param_offset_ptr = Value;
|
||||
break;
|
||||
case SQL_DESC_BIND_TYPE:
|
||||
stmt->options.param_bind_type = (SQLUINTEGER) Value;
|
||||
break;
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RETCODE SQL_API
|
||||
IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
|
||||
{
|
||||
RETCODE ret = SQL_SUCCESS;
|
||||
switch (FieldIdentifier)
|
||||
{
|
||||
case SQL_DESC_ARRAY_STATUS_PTR:
|
||||
stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
|
||||
break;
|
||||
case SQL_DESC_ROWS_PROCESSED_PTR:
|
||||
stmt->options.rowsFetched = (SQLUINTEGER *) Value;
|
||||
break;
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RETCODE SQL_API
|
||||
IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber,
|
||||
SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength)
|
||||
{
|
||||
RETCODE ret = SQL_SUCCESS;
|
||||
switch (FieldIdentifier)
|
||||
{
|
||||
case SQL_DESC_ARRAY_STATUS_PTR:
|
||||
stmt->options.param_status_ptr = (SQLUSMALLINT *) Value;
|
||||
break;
|
||||
case SQL_DESC_ROWS_PROCESSED_PTR:
|
||||
stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
|
||||
break;
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* new function */
|
||||
RETCODE SQL_API
|
||||
SQLSetDescField(SQLHDESC DescriptorHandle,
|
||||
SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
|
||||
PTR Value, SQLINTEGER BufferLength)
|
||||
{
|
||||
mylog("[[SQLSetDescField]]\n");
|
||||
return SQL_ERROR;
|
||||
RETCODE ret = SQL_SUCCESS;
|
||||
HSTMT hstmt;
|
||||
SQLUINTEGER descType;
|
||||
StatementClass *stmt;
|
||||
mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
|
||||
hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType);
|
||||
mylog("stmt=%x type=%d\n", hstmt, descType);
|
||||
stmt = (StatementClass *) hstmt;
|
||||
switch (descType)
|
||||
{
|
||||
case SQL_ATTR_APP_ROW_DESC:
|
||||
ret = ARDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
|
||||
break;
|
||||
case SQL_ATTR_APP_PARAM_DESC:
|
||||
ret = APDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
|
||||
break;
|
||||
case SQL_ATTR_IMP_ROW_DESC:
|
||||
ret = IRDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
|
||||
break;
|
||||
case SQL_ATTR_IMP_PARAM_DESC:
|
||||
ret = IPDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength);
|
||||
break;
|
||||
default:ret = SQL_ERROR;
|
||||
stmt->errornumber = STMT_INTERNAL_ERROR;
|
||||
mylog("Error not implemented\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* new fucntion */
|
||||
@ -419,7 +583,8 @@ SQLSetDescRec(SQLHDESC DescriptorHandle,
|
||||
PTR Data, SQLINTEGER *StringLength,
|
||||
SQLINTEGER *Indicator)
|
||||
{
|
||||
mylog("[[SQLsetDescRec]]\n");
|
||||
mylog("[[SQLSetDescRec]]\n");
|
||||
mylog("Error not implemented\n");
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
@ -466,16 +631,10 @@ SQLSetStmtAttr(HSTMT StatementHandle,
|
||||
{
|
||||
static char *func = "SQLSetStmtAttr";
|
||||
StatementClass *stmt = (StatementClass *) StatementHandle;
|
||||
UDWORD rowcount;
|
||||
|
||||
mylog("[[%s]] %d,%u\n", func, Attribute, Value);
|
||||
mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
|
||||
switch (Attribute)
|
||||
{
|
||||
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
|
||||
return PGAPI_ParamOptions(StatementHandle, (UWORD) Value, &rowcount);
|
||||
case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
|
||||
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
|
||||
|
||||
case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */
|
||||
case SQL_ATTR_CURSOR_SENSITIVITY: /* -2 */
|
||||
|
||||
@ -484,28 +643,41 @@ SQLSetStmtAttr(HSTMT StatementHandle,
|
||||
case SQL_ATTR_APP_ROW_DESC: /* 10010 */
|
||||
case SQL_ATTR_APP_PARAM_DESC: /* 10011 */
|
||||
case SQL_ATTR_AUTO_IPD: /* 10001 */
|
||||
/* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
|
||||
case SQL_ATTR_IMP_ROW_DESC: /* 10012 */
|
||||
case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */
|
||||
/* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
|
||||
case SQL_ATTR_IMP_ROW_DESC: /* 10012 (read-only) */
|
||||
case SQL_ATTR_IMP_PARAM_DESC: /* 10013 (read-only) */
|
||||
case SQL_ATTR_METADATA_ID: /* 10014 */
|
||||
|
||||
/*
|
||||
* case SQL_ATTR_PREDICATE_PTR: case
|
||||
* SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
|
||||
*/
|
||||
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
|
||||
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
|
||||
case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
|
||||
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
|
||||
case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
|
||||
case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
|
||||
stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER;
|
||||
stmt->errormsg = "Unsupported statement option (Set)";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
|
||||
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
|
||||
stmt->options.param_offset_ptr = (SQLUINTEGER *) Value;
|
||||
break;
|
||||
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
|
||||
stmt->options.row_offset_ptr = (SQLUINTEGER *) Value;
|
||||
break;
|
||||
|
||||
case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */
|
||||
stmt->options.bookmark_ptr = Value;
|
||||
|
||||
break;
|
||||
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
|
||||
stmt->options.param_bind_type = (SQLUINTEGER) Value;
|
||||
break;
|
||||
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
|
||||
stmt->options.param_processed_ptr = (SQLUINTEGER *) Value;
|
||||
break;
|
||||
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
|
||||
stmt->options.paramset_size = (SQLUINTEGER) Value;
|
||||
break;
|
||||
case SQL_ATTR_ROW_STATUS_PTR: /* 25 */
|
||||
stmt->options.rowStatusArray = (SQLUSMALLINT *) Value;
|
||||
@ -642,111 +814,3 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
RETCODE SQL_API
|
||||
PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
|
||||
SWORD cbInfoValueMax, SWORD FAR * pcbInfoValue)
|
||||
{
|
||||
static char *func = "PGAPI_GetInfo30";
|
||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
||||
char *p = NULL;
|
||||
int len = 0,
|
||||
value = 0;
|
||||
RETCODE result;
|
||||
|
||||
switch (fInfoType)
|
||||
{
|
||||
case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
|
||||
len = 4;
|
||||
value = 0;
|
||||
break;
|
||||
case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
|
||||
len = 4;
|
||||
value = 0;
|
||||
break;
|
||||
|
||||
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
|
||||
len = 4;
|
||||
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
|
||||
SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
|
||||
break;
|
||||
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
|
||||
len = 4;
|
||||
value = 0;
|
||||
break;
|
||||
case SQL_KEYSET_CURSOR_ATTRIBUTES1:
|
||||
len = 4;
|
||||
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE
|
||||
| SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
|
||||
| SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
|
||||
| SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
|
||||
| SQL_CA1_POS_REFRESH
|
||||
| SQL_CA1_BULK_ADD
|
||||
| SQL_CA1_BULK_UPDATE_BY_BOOKMARK
|
||||
| SQL_CA1_BULK_DELETE_BY_BOOKMARK
|
||||
| SQL_CA1_BULK_FETCH_BY_BOOKMARK
|
||||
;
|
||||
break;
|
||||
case SQL_KEYSET_CURSOR_ATTRIBUTES2:
|
||||
len = 4;
|
||||
value = SQL_CA2_OPT_ROWVER_CONCURRENCY |
|
||||
SQL_CA2_SENSITIVITY_ADDITIONS |
|
||||
SQL_CA2_SENSITIVITY_DELETIONS |
|
||||
SQL_CA2_SENSITIVITY_UPDATES;
|
||||
break;
|
||||
|
||||
case SQL_STATIC_CURSOR_ATTRIBUTES1:
|
||||
len = 4;
|
||||
value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
|
||||
SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK |
|
||||
SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION |
|
||||
SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE |
|
||||
SQL_CA1_POS_REFRESH;
|
||||
break;
|
||||
case SQL_STATIC_CURSOR_ATTRIBUTES2:
|
||||
len = 4;
|
||||
value = SQL_CA2_OPT_ROWVER_CONCURRENCY |
|
||||
SQL_CA2_SENSITIVITY_ADDITIONS |
|
||||
SQL_CA2_SENSITIVITY_DELETIONS |
|
||||
SQL_CA2_SENSITIVITY_UPDATES;
|
||||
break;
|
||||
default:
|
||||
/* unrecognized key */
|
||||
conn->errormsg = "Unrecognized key passed to SQLGetInfo.";
|
||||
conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
|
||||
CC_log_error(func, "", conn);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
result = SQL_SUCCESS;
|
||||
if (p)
|
||||
{
|
||||
/* char/binary data */
|
||||
len = strlen(p);
|
||||
|
||||
if (rgbInfoValue)
|
||||
{
|
||||
strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
|
||||
|
||||
if (len >= cbInfoValueMax)
|
||||
{
|
||||
result = SQL_SUCCESS_WITH_INFO;
|
||||
conn->errornumber = STMT_TRUNCATED;
|
||||
conn->errormsg = "The buffer was too small for tthe InfoValue.";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* numeric data */
|
||||
if (rgbInfoValue)
|
||||
{
|
||||
if (len == 2)
|
||||
*((WORD *) rgbInfoValue) = (WORD) value;
|
||||
else if (len == 4)
|
||||
*((DWORD *) rgbInfoValue) = (DWORD) value;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcbInfoValue)
|
||||
*pcbInfoValue = len;
|
||||
return result;
|
||||
}
|
||||
|
@ -342,14 +342,12 @@ PGAPI_SetConnectOption(
|
||||
break;
|
||||
|
||||
case SQL_AUTOCOMMIT:
|
||||
if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
|
||||
break;
|
||||
else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
|
||||
break;
|
||||
if (CC_is_in_trans(conn))
|
||||
{
|
||||
conn->errormsg = "Cannot switch commit mode while a transaction is in progress";
|
||||
conn->errornumber = CONN_TRANSACT_IN_PROGRES;
|
||||
CC_log_error(func, "", conn);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
CC_commit(conn);
|
||||
mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
|
||||
|
||||
switch (vParam)
|
||||
@ -475,7 +473,7 @@ PGAPI_GetConnectOption(
|
||||
break;
|
||||
|
||||
case SQL_TXN_ISOLATION: /* NOT SUPPORTED */
|
||||
*((UDWORD *) pvParam) = SQL_TXN_SERIALIZABLE;
|
||||
*((UDWORD *) pvParam) = SQL_TXN_READ_COMMITTED;
|
||||
break;
|
||||
|
||||
/* These options should be handled by driver manager */
|
||||
|
@ -742,7 +742,7 @@ parse_statement(StatementClass *stmt)
|
||||
col_stmt->internal = TRUE;
|
||||
|
||||
result = PGAPI_Columns(hcol_stmt, "", 0, "", 0,
|
||||
ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0);
|
||||
ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0, PODBC_NOT_SEARCH_PATTERN);
|
||||
|
||||
mylog(" Past PG_Columns\n");
|
||||
if (result == SQL_SUCCESS)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PODBC_NOT_SEARCH_PATTERN 1L
|
||||
|
||||
RETCODE SQL_API PGAPI_AllocConnect(HENV EnvironmentHandle,
|
||||
HDBC FAR * ConnectionHandle);
|
||||
@ -25,7 +26,8 @@ RETCODE SQL_API PGAPI_Columns(HSTMT StatementHandle,
|
||||
SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
|
||||
SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
|
||||
SQLCHAR *TableName, SQLSMALLINT NameLength3,
|
||||
SQLCHAR *ColumnName, SQLSMALLINT NameLength4);
|
||||
SQLCHAR *ColumnName, SQLSMALLINT NameLength4,
|
||||
UWORD flag);
|
||||
RETCODE SQL_API PGAPI_Connect(HDBC ConnectionHandle,
|
||||
SQLCHAR *ServerName, SQLSMALLINT NameLength1,
|
||||
SQLCHAR *UserName, SQLSMALLINT NameLength2,
|
||||
|
@ -51,6 +51,7 @@ Int4 pgtypes_defined[] = {
|
||||
PG_TYPE_BPCHAR,
|
||||
PG_TYPE_DATE,
|
||||
PG_TYPE_TIME,
|
||||
PG_TYPE_TIME_WITH_TMZONE,
|
||||
PG_TYPE_DATETIME,
|
||||
PG_TYPE_ABSTIME,
|
||||
PG_TYPE_TIMESTAMP,
|
||||
@ -227,7 +228,11 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
|
||||
|
||||
/* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
|
||||
case PG_TYPE_INT8:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_BIGINT;
|
||||
#else
|
||||
return SQL_CHAR;
|
||||
#endif /* ODBCVER */
|
||||
|
||||
case PG_TYPE_NUMERIC:
|
||||
return SQL_NUMERIC;
|
||||
@ -273,7 +278,11 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
|
||||
switch (type)
|
||||
{
|
||||
case PG_TYPE_INT8:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_C_SBIGINT;
|
||||
#else
|
||||
return SQL_C_CHAR;
|
||||
#endif
|
||||
case PG_TYPE_NUMERIC:
|
||||
return SQL_C_CHAR;
|
||||
case PG_TYPE_INT2:
|
||||
@ -287,13 +296,25 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
|
||||
case PG_TYPE_FLOAT8:
|
||||
return SQL_C_DOUBLE;
|
||||
case PG_TYPE_DATE:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_C_TYPE_DATE;
|
||||
#else
|
||||
return SQL_C_DATE;
|
||||
#endif /* ODBCVER */
|
||||
case PG_TYPE_TIME:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_C_TYPE_TIME;
|
||||
#else
|
||||
return SQL_C_TIME;
|
||||
#endif /* ODBCVER */
|
||||
case PG_TYPE_ABSTIME:
|
||||
case PG_TYPE_DATETIME:
|
||||
case PG_TYPE_TIMESTAMP:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_C_TYPE_TIMESTAMP;
|
||||
#else
|
||||
return SQL_C_TIMESTAMP;
|
||||
#endif /* ODBCVER */
|
||||
case PG_TYPE_MONEY:
|
||||
return SQL_C_FLOAT;
|
||||
case PG_TYPE_BOOL:
|
||||
@ -386,7 +407,7 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
|
||||
static Int2
|
||||
getNumericScale(StatementClass *stmt, Int4 type, int col)
|
||||
{
|
||||
Int4 atttypmod;
|
||||
Int4 atttypmod = -1;
|
||||
QResultClass *result;
|
||||
ColumnInfoClass *flds;
|
||||
|
||||
@ -405,12 +426,16 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
|
||||
{
|
||||
flds = result->fields;
|
||||
if (flds)
|
||||
return flds->adtsize[col];
|
||||
else
|
||||
{
|
||||
atttypmod = flds->atttypmod[col];
|
||||
if (atttypmod < 0 && flds->adtsize[col] > 0)
|
||||
return flds->adtsize[col];
|
||||
}
|
||||
if (atttypmod < 0)
|
||||
return PG_NUMERIC_MAX_SCALE;
|
||||
}
|
||||
|
||||
atttypmod = QR_get_atttypmod(result, col);
|
||||
else
|
||||
atttypmod = QR_get_atttypmod(result, col);
|
||||
if (atttypmod > -1)
|
||||
return (atttypmod & 0xffff);
|
||||
else
|
||||
@ -423,7 +448,7 @@ getNumericScale(StatementClass *stmt, Int4 type, int col)
|
||||
static Int4
|
||||
getNumericPrecision(StatementClass *stmt, Int4 type, int col)
|
||||
{
|
||||
Int4 atttypmod;
|
||||
Int4 atttypmod = -1;
|
||||
QResultClass *result;
|
||||
ColumnInfoClass *flds;
|
||||
|
||||
@ -442,16 +467,20 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col)
|
||||
{
|
||||
flds = result->fields;
|
||||
if (flds)
|
||||
return flds->adtsize[col];
|
||||
else
|
||||
{
|
||||
atttypmod = flds->atttypmod[col];
|
||||
if (atttypmod < 0 && flds->adtsize[col] > 0)
|
||||
return flds->adtsize[col];
|
||||
}
|
||||
if (atttypmod < 0)
|
||||
return PG_NUMERIC_MAX_PRECISION;
|
||||
}
|
||||
|
||||
atttypmod = QR_get_atttypmod(result, col);
|
||||
else
|
||||
atttypmod = QR_get_atttypmod(result, col);
|
||||
if (atttypmod > -1)
|
||||
return (atttypmod >> 16) & 0xffff;
|
||||
else
|
||||
return (QR_get_display_size(result, col) >= 0 ?
|
||||
return (QR_get_display_size(result, col) > 0 ?
|
||||
QR_get_display_size(result, col) :
|
||||
PG_NUMERIC_MAX_PRECISION);
|
||||
}
|
||||
@ -586,13 +615,19 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
|
||||
fixed = 8;
|
||||
break;
|
||||
case PG_TYPE_TIME_WITH_TMZONE:
|
||||
fixed = 11;
|
||||
if (USE_ZONE)
|
||||
fixed = 11;
|
||||
else
|
||||
fixed = 8;
|
||||
break;
|
||||
case PG_TYPE_TIMESTAMP_NO_TMZONE:
|
||||
fixed = 19;
|
||||
break;
|
||||
default:
|
||||
fixed = 22;
|
||||
if (USE_ZONE)
|
||||
fixed = 22;
|
||||
else
|
||||
fixed = 19;
|
||||
break;
|
||||
}
|
||||
scale = getTimestampScale(stmt, type, col);
|
||||
@ -677,6 +712,8 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
|
||||
Int4
|
||||
pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
|
||||
{
|
||||
int dsize;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PG_TYPE_INT2:
|
||||
@ -693,7 +730,8 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
|
||||
return 20; /* signed: 19 digits + sign */
|
||||
|
||||
case PG_TYPE_NUMERIC:
|
||||
return getNumericPrecision(stmt, type, col) + 2;
|
||||
dsize = getNumericPrecision(stmt, type, col);
|
||||
return dsize < 0 ? dsize : dsize + 2;
|
||||
|
||||
case PG_TYPE_MONEY:
|
||||
return 15; /* ($9,999,999.99) */
|
||||
@ -848,6 +886,7 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type)
|
||||
|
||||
case PG_TYPE_DATE:
|
||||
case PG_TYPE_TIME:
|
||||
case PG_TYPE_TIME_WITH_TMZONE:
|
||||
case PG_TYPE_ABSTIME:
|
||||
case PG_TYPE_DATETIME:
|
||||
case PG_TYPE_TIMESTAMP:
|
||||
@ -1013,8 +1052,14 @@ sqltype_to_default_ctype(Int2 sqltype)
|
||||
case SQL_LONGVARCHAR:
|
||||
case SQL_DECIMAL:
|
||||
case SQL_NUMERIC:
|
||||
#if (ODBCVER < 0x0300)
|
||||
case SQL_BIGINT:
|
||||
return SQL_C_CHAR;
|
||||
#else
|
||||
return SQL_C_CHAR;
|
||||
case SQL_BIGINT:
|
||||
return SQL_C_SBIGINT;
|
||||
#endif
|
||||
|
||||
case SQL_BIT:
|
||||
return SQL_C_BIT;
|
||||
@ -1041,13 +1086,25 @@ sqltype_to_default_ctype(Int2 sqltype)
|
||||
return SQL_C_BINARY;
|
||||
|
||||
case SQL_DATE:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_C_TYPE_DATE;
|
||||
#else
|
||||
return SQL_C_DATE;
|
||||
#endif /* ODBCVER */
|
||||
|
||||
case SQL_TIME:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_C_TYPE_TIME;
|
||||
#else
|
||||
return SQL_C_TIME;
|
||||
#endif /* ODBCVER */
|
||||
|
||||
case SQL_TIMESTAMP:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
return SQL_C_TYPE_TIMESTAMP;
|
||||
#else
|
||||
return SQL_C_TIMESTAMP;
|
||||
#endif /* ODBCVER */
|
||||
|
||||
default:
|
||||
/* should never happen */
|
||||
@ -1091,12 +1148,21 @@ ctype_length(Int2 ctype)
|
||||
return sizeof(UCHAR);
|
||||
|
||||
case SQL_C_DATE:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
case SQL_C_TYPE_DATE:
|
||||
#endif /* ODBCVER */
|
||||
return sizeof(DATE_STRUCT);
|
||||
|
||||
case SQL_C_TIME:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
case SQL_C_TYPE_TIME:
|
||||
#endif /* ODBCVER */
|
||||
return sizeof(TIME_STRUCT);
|
||||
|
||||
case SQL_C_TIMESTAMP:
|
||||
#if (ODBCVER >= 0x0300)
|
||||
case SQL_C_TYPE_TIMESTAMP:
|
||||
#endif /* ODBCVER */
|
||||
return sizeof(TIMESTAMP_STRUCT);
|
||||
|
||||
case SQL_C_BINARY:
|
||||
|
@ -58,7 +58,7 @@
|
||||
#define PG_TYPE_VARCHAR 1043
|
||||
#define PG_TYPE_DATE 1082
|
||||
#define PG_TYPE_TIME 1083
|
||||
#define PG_TYPE_TIMESTAMP_NO_TMZONE 1114 /* since 7.2 */
|
||||
#define PG_TYPE_TIMESTAMP_NO_TMZONE 1114 /* since 7.2 */
|
||||
#define PG_TYPE_DATETIME 1184
|
||||
#define PG_TYPE_TIME_WITH_TMZONE 1266 /* since 7.1 */
|
||||
#define PG_TYPE_TIMESTAMP 1296 /* deprecated since 7.0 */
|
||||
@ -96,4 +96,5 @@ char *pgtype_create_params(StatementClass *stmt, Int4 type);
|
||||
Int2 sqltype_to_default_ctype(Int2 sqltype);
|
||||
Int4 ctype_length(Int2 ctype);
|
||||
|
||||
#define USE_ZONE FALSE
|
||||
#endif
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* Comments: See "notice.txt" for copyright and license information.
|
||||
*
|
||||
* $Id: psqlodbc.h,v 1.56 2001/11/05 17:46:38 momjian Exp $
|
||||
* $Id: psqlodbc.h,v 1.57 2002/02/18 03:16:11 inoue Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -72,6 +72,8 @@ typedef UInt4 Oid;
|
||||
#ifndef WIN32
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#else
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/* Driver stuff */
|
||||
@ -85,7 +87,7 @@ typedef UInt4 Oid;
|
||||
#define DBMS_NAME "PostgreSQL"
|
||||
#endif /* ODBCVER */
|
||||
|
||||
#define POSTGRESDRIVERVERSION "07.01.0009"
|
||||
#define POSTGRESDRIVERVERSION "07.01.0010"
|
||||
|
||||
#ifdef WIN32
|
||||
#if (ODBCVER >= 0x0300)
|
||||
|
@ -354,8 +354,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 7,1,0,9
|
||||
PRODUCTVERSION 7,1,0,9
|
||||
FILEVERSION 7,1,0,10
|
||||
PRODUCTVERSION 7,1,0,10
|
||||
FILEFLAGSMASK 0x3L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -377,14 +377,14 @@ BEGIN
|
||||
VALUE "CompanyName", "Insight Distribution Systems\0"
|
||||
#endif
|
||||
VALUE "FileDescription", "PostgreSQL Driver\0"
|
||||
VALUE "FileVersion", " 07.01.0009\0"
|
||||
VALUE "FileVersion", " 07.01.0010\0"
|
||||
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.01.0009\0"
|
||||
VALUE "ProductVersion", " 07.01.0010\0"
|
||||
VALUE "SpecialBuild", "\0"
|
||||
END
|
||||
END
|
||||
|
@ -279,7 +279,11 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
|
||||
mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
|
||||
|
||||
if (fetch_cursor)
|
||||
{
|
||||
if (self->cache_size <= 0)
|
||||
self->cache_size = ci->drivers.fetch_max;
|
||||
tuple_size = self->cache_size;
|
||||
}
|
||||
else
|
||||
tuple_size = TUPLE_MALLOC_INC;
|
||||
|
||||
@ -359,17 +363,12 @@ QR_close(QResultClass *self)
|
||||
{
|
||||
mylog("QResult: END transaction on conn=%u\n", self->conn);
|
||||
|
||||
res = CC_send_query(self->conn, "END", NULL);
|
||||
|
||||
CC_set_no_trans(self->conn);
|
||||
|
||||
if (res == NULL)
|
||||
if (!CC_commit(self->conn))
|
||||
{
|
||||
self->status = PGRES_FATAL_ERROR;
|
||||
QR_set_message(self, "Error ending transaction.");
|
||||
return FALSE;
|
||||
}
|
||||
QR_Destructor(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1296,7 +1296,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count)
|
||||
if (rcnt == 1)
|
||||
{
|
||||
QR_set_position(qres, 0);
|
||||
tuplen = res->tupleField;
|
||||
tuplen = qres->tupleField;
|
||||
for (i = 0; i < res->num_fields; i++)
|
||||
{
|
||||
if (tupleo[i].value)
|
||||
@ -1416,6 +1416,8 @@ SC_pos_update(StatementClass *stmt,
|
||||
RETCODE ret;
|
||||
char *tidval,
|
||||
*oidval;
|
||||
UInt4 offset;
|
||||
Int4 *used;
|
||||
|
||||
mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, stmt->result->base, stmt->fi, stmt->ti);
|
||||
if (!(res = stmt->result))
|
||||
@ -1438,12 +1440,17 @@ SC_pos_update(StatementClass *stmt,
|
||||
|
||||
sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
|
||||
num_cols = stmt->nfld;
|
||||
if (stmt->options.row_offset_ptr)
|
||||
offset = *stmt->options.row_offset_ptr;
|
||||
else
|
||||
offset = 0;
|
||||
for (i = upd_cols = 0; i < num_cols; i++)
|
||||
{
|
||||
if (bindings[i].used)
|
||||
if (used = bindings[i].used, used != NULL)
|
||||
{
|
||||
mylog("%d used=%d\n", i, *bindings[i].used);
|
||||
if (*bindings[i].used != SQL_IGNORE)
|
||||
used += (offset >> 2);
|
||||
mylog("%d used=%d\n", i, *used);
|
||||
if (*used != SQL_IGNORE)
|
||||
{
|
||||
if (upd_cols)
|
||||
sprintf(updstr, "%s, \"%s\" = ?", updstr, stmt->fi[i]->name);
|
||||
@ -1468,12 +1475,15 @@ SC_pos_update(StatementClass *stmt,
|
||||
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
|
||||
return SQL_ERROR;
|
||||
qstmt = (StatementClass *) hstmt;
|
||||
qstmt->options.param_bind_type = stmt->options.bind_size;
|
||||
qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
|
||||
for (i = j = 0; i < num_cols; i++)
|
||||
{
|
||||
if (bindings[i].used)
|
||||
if (used = bindings[i].used, used != NULL)
|
||||
{
|
||||
mylog("%d used=%d\n", i, *bindings[i].used);
|
||||
if (*bindings[i].used != SQL_IGNORE)
|
||||
used += (offset >> 2);
|
||||
mylog("%d used=%d\n", i, *used);
|
||||
if (*used != SQL_IGNORE)
|
||||
{
|
||||
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
|
||||
SQL_PARAM_INPUT, bindings[i].returntype,
|
||||
@ -1486,6 +1496,7 @@ SC_pos_update(StatementClass *stmt,
|
||||
}
|
||||
}
|
||||
}
|
||||
qstmt->exec_start_row = qstmt->exec_end_row = irow;
|
||||
ret = PGAPI_ExecDirect(hstmt, updstr, strlen(updstr));
|
||||
if (ret == SQL_ERROR)
|
||||
{
|
||||
@ -1533,6 +1544,19 @@ SC_pos_update(StatementClass *stmt,
|
||||
}
|
||||
else
|
||||
ret = SQL_SUCCESS_WITH_INFO;
|
||||
if (stmt->options.rowStatusArray)
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case SQL_SUCCESS:
|
||||
stmt->options.rowStatusArray[irow] = SQL_ROW_UPDATED;
|
||||
break;
|
||||
case SQL_SUCCESS_WITH_INFO:
|
||||
stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
RETCODE SQL_API
|
||||
@ -1606,6 +1630,18 @@ SC_pos_delete(StatementClass *stmt,
|
||||
}
|
||||
if (qres)
|
||||
QR_Destructor(qres);
|
||||
if (stmt->options.rowStatusArray)
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case SQL_SUCCESS:
|
||||
stmt->options.rowStatusArray[irow] = SQL_ROW_DELETED;
|
||||
break;
|
||||
case SQL_SUCCESS_WITH_INFO:
|
||||
stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
RETCODE SQL_API
|
||||
@ -1616,10 +1652,13 @@ SC_pos_add(StatementClass *stmt,
|
||||
add_cols,
|
||||
i;
|
||||
HSTMT hstmt;
|
||||
StatementClass *qstmt;
|
||||
QResultClass *res;
|
||||
BindInfoClass *bindings = stmt->bindings;
|
||||
char addstr[4096];
|
||||
RETCODE ret;
|
||||
UInt4 offset;
|
||||
Int4 *used;
|
||||
|
||||
mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti);
|
||||
if (!(res = stmt->result))
|
||||
@ -1635,12 +1674,20 @@ SC_pos_add(StatementClass *stmt,
|
||||
sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
|
||||
if (PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt) != SQL_SUCCESS)
|
||||
return SQL_ERROR;
|
||||
if (stmt->options.row_offset_ptr)
|
||||
offset = *stmt->options.row_offset_ptr;
|
||||
else
|
||||
offset = 0;
|
||||
qstmt = (StatementClass *) hstmt;
|
||||
qstmt->options.param_bind_type = stmt->options.bind_size;
|
||||
qstmt->options.param_offset_ptr = stmt->options.row_offset_ptr;
|
||||
for (i = add_cols = 0; i < num_cols; i++)
|
||||
{
|
||||
if (bindings[i].used)
|
||||
if (used = bindings[i].used, used != NULL)
|
||||
{
|
||||
mylog("%d used=%d\n", i, *bindings[i].used);
|
||||
if (*bindings[i].used != SQL_IGNORE)
|
||||
used += (offset >> 2);
|
||||
mylog("%d used=%d\n", i, *used);
|
||||
if (*used != SQL_IGNORE)
|
||||
{
|
||||
if (add_cols)
|
||||
sprintf(addstr, "%s, \"%s\"", addstr, stmt->fi[i]->name);
|
||||
@ -1661,7 +1708,6 @@ SC_pos_add(StatementClass *stmt,
|
||||
}
|
||||
if (add_cols > 0)
|
||||
{
|
||||
StatementClass *qstmt = (StatementClass *) hstmt;
|
||||
|
||||
sprintf(addstr, "%s) values (", addstr);
|
||||
for (i = 0; i < add_cols; i++)
|
||||
@ -1673,6 +1719,7 @@ SC_pos_add(StatementClass *stmt,
|
||||
}
|
||||
strcat(addstr, ")");
|
||||
mylog("addstr=%s\n", addstr);
|
||||
qstmt->exec_start_row = qstmt->exec_end_row = irow;
|
||||
ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr));
|
||||
if (ret == SQL_NEED_DATA) /* must be fixed */
|
||||
{
|
||||
@ -1718,6 +1765,18 @@ SC_pos_add(StatementClass *stmt,
|
||||
else
|
||||
ret = SQL_SUCCESS_WITH_INFO;
|
||||
PGAPI_FreeStmt(hstmt, SQL_DROP);
|
||||
if (stmt->options.rowStatusArray)
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case SQL_SUCCESS:
|
||||
stmt->options.rowStatusArray[irow] = SQL_ROW_ADDED;
|
||||
break;
|
||||
case SQL_SUCCESS_WITH_INFO:
|
||||
stmt->options.rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -263,6 +263,9 @@ SC_Constructor(void)
|
||||
|
||||
rv->data_at_exec = -1;
|
||||
rv->current_exec_param = -1;
|
||||
rv->exec_start_row = -1;
|
||||
rv->exec_end_row = -1;
|
||||
rv->exec_current_row = -1;
|
||||
rv->put_data = FALSE;
|
||||
|
||||
rv->lobj_fd = -1;
|
||||
@ -404,6 +407,9 @@ SC_free_params(StatementClass *self, char option)
|
||||
free(self->parameters);
|
||||
self->parameters = NULL;
|
||||
self->parameters_allocated = 0;
|
||||
self->exec_start_row = -1;
|
||||
self->exec_end_row = -1;
|
||||
self->exec_current_row = -1;
|
||||
}
|
||||
|
||||
mylog("SC_free_params: EXIT\n");
|
||||
@ -778,10 +784,12 @@ SC_fetch(StatementClass *self)
|
||||
if (self->bookmark.buffer)
|
||||
{
|
||||
char buf[32];
|
||||
UInt4 offset = self->options.row_offset_ptr ? *self->options.row_offset_ptr : 0;
|
||||
|
||||
sprintf(buf, "%ld", SC_get_bookmark(self));
|
||||
result = copy_and_convert_field(self, 0, buf,
|
||||
SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used);
|
||||
SQL_C_ULONG, self->bookmark.buffer + offset, 0,
|
||||
self->bookmark.used ? self->bookmark.used + (offset >> 2) : NULL);
|
||||
}
|
||||
|
||||
#ifdef DRIVER_CURSOR_IMPLEMENT
|
||||
@ -892,10 +900,7 @@ SC_execute(StatementClass *self)
|
||||
{
|
||||
static char *func = "SC_execute";
|
||||
ConnectionClass *conn;
|
||||
QResultClass *res;
|
||||
char ok,
|
||||
was_ok,
|
||||
was_nonfatal;
|
||||
char was_ok, was_nonfatal;
|
||||
Int2 oldstatus,
|
||||
numcols;
|
||||
QueryInfo qi;
|
||||
@ -920,30 +925,13 @@ SC_execute(StatementClass *self)
|
||||
(!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
|
||||
{
|
||||
mylog(" about to begin a transaction on statement = %u\n", self);
|
||||
res = CC_send_query(conn, "BEGIN", NULL);
|
||||
if (QR_aborted(res))
|
||||
if (!CC_begin(conn))
|
||||
{
|
||||
self->errormsg = "Could not begin a transaction";
|
||||
self->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", self);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
ok = QR_command_successful(res);
|
||||
|
||||
mylog("SC_exec: begin ok = %d, status = %d\n", ok, QR_get_status(res));
|
||||
|
||||
QR_Destructor(res);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
self->errormsg = "Could not begin a transaction";
|
||||
self->errornumber = STMT_EXEC_ERROR;
|
||||
SC_log_error(func, "", self);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
else
|
||||
CC_set_in_trans(conn);
|
||||
}
|
||||
|
||||
oldstatus = conn->status;
|
||||
@ -1008,11 +996,7 @@ SC_execute(StatementClass *self)
|
||||
* transactions must be committed. (Hiroshi, 02/11/2001)
|
||||
*/
|
||||
if (!self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
|
||||
{
|
||||
res = CC_send_query(conn, "COMMIT", NULL);
|
||||
QR_Destructor(res);
|
||||
CC_set_no_trans(conn);
|
||||
}
|
||||
CC_commit(conn);
|
||||
}
|
||||
|
||||
conn->status = oldstatus;
|
||||
|
@ -75,6 +75,7 @@ typedef enum
|
||||
#define STMT_PROGRAM_TYPE_OUT_OF_RANGE 26
|
||||
#define STMT_BAD_ERROR 27
|
||||
#define STMT_INVALID_OPTION_IDENTIFIER 28
|
||||
#define STMT_RETURN_NULL_WITHOUT_INDICATOR 29
|
||||
|
||||
/* statement types */
|
||||
enum
|
||||
@ -207,6 +208,9 @@ struct StatementClass_
|
||||
char *stmt_with_params; /* statement after parameter
|
||||
* substitution */
|
||||
int stmt_size_limit;
|
||||
int exec_start_row;
|
||||
int exec_end_row;
|
||||
int exec_current_row;
|
||||
|
||||
char pre_executing; /* This statement is prematurely executing */
|
||||
char inaccurate_result; /* Current status is PREMATURE but
|
||||
|
Loading…
x
Reference in New Issue
Block a user