Commit e5cff3fe authored by Hiroshi Inoue's avatar Hiroshi Inoue

Get rid of the following size limit.

1) Query size limit(was 65536) for >=7.0 servers.
2) Text size limit(was 8190) for 7.1 servers.
parent f3c1ae58
...@@ -915,6 +915,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) ...@@ -915,6 +915,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
char swallow; char swallow;
int id; int id;
SocketClass *sock = self->sock; SocketClass *sock = self->sock;
int maxlen;
/* ERROR_MSG_LENGTH is suffcient */ /* ERROR_MSG_LENGTH is suffcient */
static char msgbuffer[ERROR_MSG_LENGTH + 1]; static char msgbuffer[ERROR_MSG_LENGTH + 1];
...@@ -926,7 +927,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) ...@@ -926,7 +927,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
qlog("conn=%u, query='%s'\n", self, query); qlog("conn=%u, query='%s'\n", self, query);
/* Indicate that we are sending a query to the backend */ /* Indicate that we are sending a query to the backend */
if (strlen(query) > MAX_MESSAGE_LEN - 2) maxlen = CC_get_max_query_len(self);
if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
{ {
self->errornumber = CONNECTION_MSG_TOO_LONG; self->errornumber = CONNECTION_MSG_TOO_LONG;
self->errormsg = "Query string is too long"; self->errormsg = "Query string is too long";
...@@ -1643,3 +1645,18 @@ CC_log_error(char *func, char *desc, ConnectionClass *self) ...@@ -1643,3 +1645,18 @@ CC_log_error(char *func, char *desc, ConnectionClass *self)
qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc); qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
#undef PRN_NULLCHECK #undef PRN_NULLCHECK
} }
int CC_get_max_query_len(const ConnectionClass *conn)
{
int value;
/* Long Queries in 7.0+ */
if (PG_VERSION_GE(conn, 7.0))
value = 0 /* MAX_STATEMENT_LEN */;
/* Prior to 7.0 we used 2*BLCKSZ */
else if (PG_VERSION_GE(conn, 6.5))
value = (2 * BLCKSZ);
else
/* Prior to 6.5 we used BLCKSZ */
value = BLCKSZ;
return value;
}
...@@ -307,6 +307,6 @@ void CC_lookup_lo(ConnectionClass *conn); ...@@ -307,6 +307,6 @@ void CC_lookup_lo(ConnectionClass *conn);
void CC_lookup_pg_version(ConnectionClass *conn); void CC_lookup_pg_version(ConnectionClass *conn);
void CC_initialize_pg_version(ConnectionClass *conn); void CC_initialize_pg_version(ConnectionClass *conn);
void CC_log_error(char *func, char *desc, ConnectionClass *self); void CC_log_error(char *func, char *desc, ConnectionClass *self);
int CC_get_max_query_len(const ConnectionClass *self);
#endif #endif
/*------- /*-------
* Module: convert.c * Module: convert.c
* *
* Description: This module contains routines related to * Description: This module contains routines related to
* converting parameters and columns into requested data types. * converting parameters and columns into requested data types.
...@@ -190,8 +190,12 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -190,8 +190,12 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
int bind_row = stmt->bind_row; int bind_row = stmt->bind_row;
int bind_size = stmt->options.bind_size; int bind_size = stmt->options.bind_size;
int result = COPY_OK; int result = COPY_OK;
char tempBuf[TEXT_FIELD_SIZE + 5]; BOOL changed;
static char *tempBuf= NULL;
static unsigned int tempBuflen = 0;
if (!tempBuf)
tempBuflen = 0;
/*--------- /*---------
* rgbValueOffset is *ONLY* for character and binary data. * rgbValueOffset is *ONLY* for character and binary data.
* pcbValueOffset is for computing any pcbValue location * pcbValueOffset is for computing any pcbValue location
...@@ -437,23 +441,62 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -437,23 +441,62 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
break; break;
default: default:
/* convert linefeeds to carriage-return/linefeed */ if (stmt->current_col >= 0 && stmt->bindings[stmt->current_col].data_left == -2)
len = convert_linefeeds(value, tempBuf, sizeof(tempBuf)); stmt->bindings[stmt->current_col].data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be needed for ADO ? */
ptr = tempBuf; if (stmt->current_col < 0 || stmt->bindings[stmt->current_col].data_left < 0)
{
/* convert linefeeds to carriage-return/linefeed */
len = convert_linefeeds(value, NULL, 0, &changed);
if (cbValueMax == 0) /* just returns length info */
{
result = COPY_RESULT_TRUNCATED;
break;
}
if (changed || len >= cbValueMax)
{
if (len >= (int) tempBuflen)
{
tempBuf = realloc(tempBuf, len + 1);
tempBuflen = len + 1;
}
convert_linefeeds(value, tempBuf, tempBuflen, &changed);
ptr = tempBuf;
}
else
{
if (tempBuf)
{
free(tempBuf);
tempBuf = NULL;
}
ptr = value;
}
}
else
ptr = tempBuf;
mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr); mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
if (stmt->current_col >= 0) if (stmt->current_col >= 0)
{ {
if (stmt->bindings[stmt->current_col].data_left == 0) if (stmt->bindings[stmt->current_col].data_left == 0)
{
if (tempBuf)
{
free(tempBuf);
tempBuf = NULL;
}
/* The following seems to be needed for ADO ? */
stmt->bindings[stmt->current_col].data_left = -2;
return COPY_NO_DATA_FOUND; return COPY_NO_DATA_FOUND;
}
else if (stmt->bindings[stmt->current_col].data_left > 0) else if (stmt->bindings[stmt->current_col].data_left > 0)
{ {
ptr += len - stmt->bindings[stmt->current_col].data_left; ptr += strlen(ptr) - stmt->bindings[stmt->current_col].data_left;
len = stmt->bindings[stmt->current_col].data_left; len = stmt->bindings[stmt->current_col].data_left;
} }
else else
stmt->bindings[stmt->current_col].data_left = strlen(ptr); stmt->bindings[stmt->current_col].data_left = len;
} }
if (cbValueMax > 0) if (cbValueMax > 0)
...@@ -461,7 +504,8 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -461,7 +504,8 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len; copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len;
/* Copy the data */ /* Copy the data */
strncpy_null(rgbValueBindRow, ptr, copy_len + 1); memcpy(rgbValueBindRow, ptr, copy_len);
rgbValueBindRow[copy_len] = '\0';
/* Adjust data_left for next time */ /* Adjust data_left for next time */
if (stmt->current_col >= 0) if (stmt->current_col >= 0)
...@@ -472,8 +516,16 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -472,8 +516,16 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
* Finally, check for truncation so that proper status can * Finally, check for truncation so that proper status can
* be returned * be returned
*/ */
if (len >= cbValueMax) if (cbValueMax > 0 && len >= cbValueMax)
result = COPY_RESULT_TRUNCATED; result = COPY_RESULT_TRUNCATED;
else
{
if (tempBuf)
{
free(tempBuf);
tempBuf = NULL;
}
}
mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow); mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
...@@ -629,14 +681,23 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -629,14 +681,23 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
/* truncate if necessary */ /* truncate if necessary */
/* convert octal escapes to bytes */ /* convert octal escapes to bytes */
len = convert_from_pgbinary(value, tempBuf, sizeof(tempBuf)); if (len = strlen(value), len >= (int) tempBuflen)
{
tempBuf = realloc(tempBuf, len + 1);
tempBuflen = len + 1;
}
len = convert_from_pgbinary(value, tempBuf, tempBuflen);
ptr = tempBuf; ptr = tempBuf;
if (stmt->current_col >= 0) if (stmt->current_col >= 0)
{ {
/* No more data left for this column */ /* No more data left for this column */
if (stmt->bindings[stmt->current_col].data_left == 0) if (stmt->bindings[stmt->current_col].data_left == 0)
{
free(tempBuf);
tempBuf = NULL;
return COPY_NO_DATA_FOUND; return COPY_NO_DATA_FOUND;
}
/* /*
* Second (or more) call to SQLGetData so move the * Second (or more) call to SQLGetData so move the
...@@ -673,6 +734,11 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -673,6 +734,11 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
if (len > cbValueMax) if (len > cbValueMax)
result = COPY_RESULT_TRUNCATED; result = COPY_RESULT_TRUNCATED;
if (tempBuf)
{
free(tempBuf);
tempBuf = NULL;
}
mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len); mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
break; break;
...@@ -690,10 +756,181 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 ...@@ -690,10 +756,181 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
} }
/*--------------------------------------------------------------------
* Functions/Macros to get rid of query size limit.
*
* I always used the follwoing macros to convert from
* old_statement to new_statement. Please improve it
* if you have a better way. Hiroshi 2001/05/22
*--------------------------------------------------------------------
*/
#define INIT_MIN_ALLOC 4096
static int enlarge_statement(StatementClass *stmt, unsigned int newsize)
{
unsigned int newalsize = INIT_MIN_ALLOC;
static char *func = "enlarge_statement";
if (stmt->stmt_size_limit > 0 && stmt->stmt_size_limit < (int) newsize)
{
stmt->errormsg = "Query buffer overflow in copy_statement_with_parameters";
stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt);
return -1;
}
while (newalsize <= newsize)
newalsize *= 2;
if (!(stmt->stmt_with_params = realloc(stmt->stmt_with_params, newalsize)))
{
stmt->errormsg = "Query buffer allocate error in copy_statement_with_parameters";
stmt->errornumber = STMT_EXEC_ERROR;
SC_log_error(func, "", stmt);
return 0;
}
return newalsize;
}
/*----------
* Enlarge stmt_with_params if necessary.
*----------
*/
#define ENLARGE_NEWSTATEMENT(newpos) \
if (newpos >= new_stsize) \
{ \
if ((new_stsize = enlarge_statement(stmt, newpos)) <= 0) \
return SQL_ERROR; \
new_statement = stmt->stmt_with_params; \
}
/*----------
* Initialize stmt_with_params, new_statement etc.
*----------
*/
#define CVT_INIT(size) \
{ \
if (stmt->stmt_with_params) \
free(stmt->stmt_with_params); \
if (stmt->stmt_size_limit > 0) \
new_stsize = stmt->stmt_size_limit; \
else \
{ \
new_stsize = INIT_MIN_ALLOC; \
while (new_stsize <= size) \
new_stsize *= 2; \
} \
new_statement = malloc(new_stsize); \
stmt->stmt_with_params = new_statement; \
npos = 0; \
new_statement[0] = '\0'; \
}
/*----------
* Terminate the stmt_with_params string with NULL.
*----------
*/
#define CVT_TERMINATE { new_statement[npos] = '\0'; }
/*----------
* Append a data.
*----------
*/
#define CVT_APPEND_DATA(s, len) \
{ \
unsigned int newpos = npos + len; \
ENLARGE_NEWSTATEMENT(newpos) \
memcpy(&new_statement[npos], s, len); \
npos = newpos; \
new_statement[npos] = '\0'; \
}
/*----------
* Append a string.
*----------
*/
#define CVT_APPEND_STR(s) \
{ \
unsigned int len = strlen(s); \
CVT_APPEND_DATA(s, len); \
}
/*----------
* Append a char.
*----------
*/
#define CVT_APPEND_CHAR(c) \
{ \
ENLARGE_NEWSTATEMENT(npos + 1); \
new_statement[npos++] = c; \
}
/*----------
* Append a binary data.
* Newly reqeuired size may be overestimated currently.
*----------
*/
#define CVT_APPEND_BINARY(buf, used) \
{ \
unsigned int newlimit = npos + 5 * used; \
ENLARGE_NEWSTATEMENT(newlimit); \
npos += convert_to_pgbinary(buf, &new_statement[npos], used); \
}
/*----------
*
*----------
*/
#define CVT_SPECIAL_CHARS(buf, used) \
{ \
int cnvlen = convert_special_chars(buf, NULL, used); \
unsigned int newlimit = npos + cnvlen; \
\
ENLARGE_NEWSTATEMENT(newlimit); \
convert_special_chars(buf, &new_statement[npos], used); \
npos += cnvlen; \
}
/*----------
* Check if the statement is
* SELECT ... INTO table FROM .....
* This isn't really a strict check but ...
*----------
*/
static BOOL
into_table_from(const char *stmt)
{
if (strnicmp(stmt, "into", 4))
return FALSE;
stmt += 4;
if (!isspace((unsigned char) *stmt))
return FALSE;
while (isspace((unsigned char) *(++stmt)));
switch (*stmt)
{
case '\0':
case ',':
case '\'':
return FALSE;
case '\"': /* double quoted table name ? */
do
{
do
{
while (*(++stmt) != '\"' && *stmt);
}
while (*stmt && *(++stmt) == '\"');
while (*stmt && !isspace((unsigned char) *stmt) && *stmt != '\"') stmt++;
}
while (*stmt == '\"');
break;
default:
while (!isspace((unsigned char) *(++stmt)));
break;
}
if (! *stmt)
return FALSE;
while (isspace((unsigned char) *(++stmt)));
if (strnicmp(stmt, "from", 4))
return FALSE;
return isspace((unsigned char) stmt[4]);
}
/* /*
* This function inserts parameters into an SQL statements. * This function inserts parameters into an SQL statements.
* It will also modify a SELECT statement for use with declare/fetch cursors. * It will also modify a SELECT statement for use with declare/fetch cursors.
* This function no longer does any dynamic memory allocation! * This function does a dynamic memory allocation to get rid of query siz elimit!
*/ */
int int
copy_statement_with_parameters(StatementClass *stmt) copy_statement_with_parameters(StatementClass *stmt)
...@@ -704,22 +941,25 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -704,22 +941,25 @@ copy_statement_with_parameters(StatementClass *stmt)
oldstmtlen; oldstmtlen;
char param_string[128], char param_string[128],
tmp[256], tmp[256],
cbuf[TEXT_FIELD_SIZE + 5]; cbuf[PG_NUMERIC_MAX_PRECISION * 2]; /* seems big enough to handle the data in this function */
int param_number; int param_number;
Int2 param_ctype, Int2 param_ctype,
param_sqltype; param_sqltype;
char *old_statement = stmt->statement; char *old_statement = stmt->statement;
char *new_statement = stmt->stmt_with_params; char *new_statement = stmt->stmt_with_params;
unsigned int new_stsize = 0;
SIMPLE_TIME st; SIMPLE_TIME st;
time_t t = time(NULL); time_t t = time(NULL);
struct tm *tim; struct tm *tim;
SDWORD used; SDWORD used;
char *buffer, char *buffer,
*buf; *buf;
char in_quote = FALSE; BOOL in_quote = FALSE, in_dquote = FALSE, in_escape = FALSE;
Oid lobj_oid; Oid lobj_oid;
int lobj_fd, int lobj_fd,
retval; retval;
BOOL check_select_into = FALSE; /* select into check */
unsigned int declare_pos;
if (!old_statement) if (!old_statement)
...@@ -740,43 +980,66 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -740,43 +980,66 @@ copy_statement_with_parameters(StatementClass *stmt)
if (stmt->cursor_name[0] == '\0') if (stmt->cursor_name[0] == '\0')
sprintf(stmt->cursor_name, "SQL_CUR%p", stmt); sprintf(stmt->cursor_name, "SQL_CUR%p", stmt);
oldstmtlen = strlen(old_statement);
CVT_INIT(oldstmtlen);
/* For selects, prepend a declare cursor to the statement */ /* For selects, prepend a declare cursor to the statement */
if (stmt->statement_type == STMT_TYPE_SELECT && globals.use_declarefetch) if (stmt->statement_type == STMT_TYPE_SELECT && globals.use_declarefetch)
{ {
sprintf(new_statement, "declare %s cursor for ", stmt->cursor_name); sprintf(new_statement, "declare %s cursor for ", stmt->cursor_name);
npos = strlen(new_statement); npos = strlen(new_statement);
} check_select_into = TRUE;
else declare_pos = npos;
{
new_statement[0] = '0';
npos = 0;
} }
param_number = -1; param_number = -1;
oldstmtlen = strlen(old_statement);
#ifdef MULTIBYTE #ifdef MULTIBYTE
multibyte_init(); multibyte_init();
#endif #endif
for (opos = 0; opos < oldstmtlen; opos++) for (opos = 0; opos < oldstmtlen; opos++)
{ {
#ifdef MULTIBYTE
if (multibyte_char_check(old_statement[opos]) != 0)
{
CVT_APPEND_CHAR(old_statement[opos]);
continue;
}
/*
* From here we are guaranteed to handle a
* 1-byte character.
*/
#endif
/* Squeeze carriage-return/linefeed pairs to linefeed only */ /* Squeeze carriage-return/linefeed pairs to linefeed only */
if (old_statement[opos] == '\r' && opos + 1 < oldstmtlen && if (old_statement[opos] == '\r' && opos + 1 < oldstmtlen &&
old_statement[opos + 1] == '\n') old_statement[opos + 1] == '\n')
continue; continue;
else if (in_escape) /* escape check */
{
in_escape = FALSE;
CVT_APPEND_CHAR(old_statement[opos]);
continue;
}
else if (in_quote || in_dquote) /* quote/double quote check */
{
if (old_statement[opos] == '\'' && in_quote)
in_quote = FALSE;
else if (old_statement[opos] == '\"' && in_dquote)
in_dquote = FALSE;
CVT_APPEND_CHAR(old_statement[opos]);
continue;
}
/*
* From here we are guranteed to be in neither
* an escape nor a quote nor a double quote.
*/
/* /*
* Handle literals (date, time, timestamp) and ODBC scalar * Handle literals (date, time, timestamp) and ODBC scalar
* functions * functions
*/ */
#ifdef MULTIBYTE
else if (multibyte_char_check(old_statement[opos]) == 0 && old_statement[opos] == '{')
{
#else
else if (old_statement[opos] == '{') else if (old_statement[opos] == '{')
{ {
#endif
char *esc; char *esc;
char *begin = &old_statement[opos + 1]; char *begin = &old_statement[opos + 1];
...@@ -796,13 +1059,12 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -796,13 +1059,12 @@ copy_statement_with_parameters(StatementClass *stmt)
esc = convert_escape(begin); esc = convert_escape(begin);
if (esc) if (esc)
{ {
memcpy(&new_statement[npos], esc, strlen(esc)); CVT_APPEND_STR(esc);
npos += strlen(esc);
} }
else else
{ /* it's not a valid literal so just copy */ { /* it's not a valid literal so just copy */
*end = '}'; *end = '}';
new_statement[npos++] = old_statement[opos]; CVT_APPEND_CHAR(old_statement[opos]);
continue; continue;
} }
...@@ -816,14 +1078,26 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -816,14 +1078,26 @@ copy_statement_with_parameters(StatementClass *stmt)
* so. All the queries I've seen expect the driver to put quotes * so. All the queries I've seen expect the driver to put quotes
* if needed. * if needed.
*/ */
else if (old_statement[opos] == '?' && !in_quote) else if (old_statement[opos] == '?')
; /* ok */ ; /* ok */
else else
{ {
if (old_statement[opos] == '\'') if (old_statement[opos] == '\'')
in_quote = (in_quote ? FALSE : TRUE); in_quote = TRUE;
else if (old_statement[opos] == '\\')
new_statement[npos++] = old_statement[opos]; in_escape = TRUE;
else if (old_statement[opos] == '\"')
in_dquote = TRUE;
else if (check_select_into && /* select into check */
opos > 0 &&
isspace((unsigned char) old_statement[opos - 1]) &&
into_table_from(&old_statement[opos]))
{
stmt->statement_type = STMT_TYPE_CREATE;
memmove(new_statement, new_statement + declare_pos, npos - declare_pos);
npos -= declare_pos;
}
CVT_APPEND_CHAR(old_statement[opos]);
continue; continue;
} }
...@@ -836,14 +1110,13 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -836,14 +1110,13 @@ copy_statement_with_parameters(StatementClass *stmt)
{ {
if (stmt->pre_executing) if (stmt->pre_executing)
{ {
strcpy(&new_statement[npos], "NULL"); CVT_APPEND_STR("NULL");
npos += 4;
stmt->inaccurate_result = TRUE; stmt->inaccurate_result = TRUE;
continue; continue;
} }
else else
{ {
new_statement[npos++] = '?'; CVT_APPEND_CHAR('?');
continue; continue;
} }
} }
...@@ -863,8 +1136,7 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -863,8 +1136,7 @@ copy_statement_with_parameters(StatementClass *stmt)
/* Handle NULL parameter data */ /* Handle NULL parameter data */
if (used == SQL_NULL_DATA) if (used == SQL_NULL_DATA)
{ {
strcpy(&new_statement[npos], "NULL"); CVT_APPEND_STR("NULL");
npos += 4;
continue; continue;
} }
...@@ -876,14 +1148,13 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -876,14 +1148,13 @@ copy_statement_with_parameters(StatementClass *stmt)
{ {
if (stmt->pre_executing) if (stmt->pre_executing)
{ {
strcpy(&new_statement[npos], "NULL"); CVT_APPEND_STR("NULL");
npos += 4;
stmt->inaccurate_result = TRUE; stmt->inaccurate_result = TRUE;
continue; continue;
} }
else else
{ {
new_statement[npos++] = '?'; CVT_APPEND_CHAR('?');
continue; continue;
} }
} }
...@@ -1002,7 +1273,7 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1002,7 +1273,7 @@ copy_statement_with_parameters(StatementClass *stmt)
/* error */ /* error */
stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters"; stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
new_statement[npos] = '\0'; /* just in case */ CVT_TERMINATE /* just in case */
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
...@@ -1018,20 +1289,18 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1018,20 +1289,18 @@ copy_statement_with_parameters(StatementClass *stmt)
case SQL_VARCHAR: case SQL_VARCHAR:
case SQL_LONGVARCHAR: case SQL_LONGVARCHAR:
new_statement[npos++] = '\''; /* Open Quote */ CVT_APPEND_CHAR('\''); /* Open Quote */
/* it was a SQL_C_CHAR */ /* it was a SQL_C_CHAR */
if (buf) if (buf)
{ {
convert_special_chars(buf, &new_statement[npos], used); CVT_SPECIAL_CHARS(buf, used);
npos += strlen(&new_statement[npos]);
} }
/* it was a numeric type */ /* it was a numeric type */
else if (param_string[0] != '\0') else if (param_string[0] != '\0')
{ {
strcpy(&new_statement[npos], param_string); CVT_APPEND_STR(param_string);
npos += strlen(param_string);
} }
/* it was date,time,timestamp -- use m,d,y,hh,mm,ss */ /* it was date,time,timestamp -- use m,d,y,hh,mm,ss */
...@@ -1040,11 +1309,10 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1040,11 +1309,10 @@ copy_statement_with_parameters(StatementClass *stmt)
sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
st.y, st.m, st.d, st.hh, st.mm, st.ss); st.y, st.m, st.d, st.hh, st.mm, st.ss);
strcpy(&new_statement[npos], tmp); CVT_APPEND_STR(tmp);
npos += strlen(tmp);
} }
new_statement[npos++] = '\''; /* Close Quote */ CVT_APPEND_CHAR('\''); /* Close Quote */
break; break;
...@@ -1057,8 +1325,7 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1057,8 +1325,7 @@ copy_statement_with_parameters(StatementClass *stmt)
sprintf(tmp, "'%.4d-%.2d-%.2d'", st.y, st.m, st.d); sprintf(tmp, "'%.4d-%.2d-%.2d'", st.y, st.m, st.d);
strcpy(&new_statement[npos], tmp); CVT_APPEND_STR(tmp);
npos += strlen(tmp);
break; break;
case SQL_TIME: case SQL_TIME:
...@@ -1070,8 +1337,7 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1070,8 +1337,7 @@ copy_statement_with_parameters(StatementClass *stmt)
sprintf(tmp, "'%.2d:%.2d:%.2d'", st.hh, st.mm, st.ss); sprintf(tmp, "'%.2d:%.2d:%.2d'", st.hh, st.mm, st.ss);
strcpy(&new_statement[npos], tmp); CVT_APPEND_STR(tmp);
npos += strlen(tmp);
break; break;
case SQL_TIMESTAMP: case SQL_TIMESTAMP:
...@@ -1085,21 +1351,20 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1085,21 +1351,20 @@ copy_statement_with_parameters(StatementClass *stmt)
sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'", sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'",
st.y, st.m, st.d, st.hh, st.mm, st.ss); st.y, st.m, st.d, st.hh, st.mm, st.ss);
strcpy(&new_statement[npos], tmp); CVT_APPEND_STR(tmp);
npos += strlen(tmp);
break; break;
case SQL_BINARY: case SQL_BINARY:
case SQL_VARBINARY:/* non-ascii characters should be case SQL_VARBINARY:/* non-ascii characters should be
* converted to octal */ * converted to octal */
new_statement[npos++] = '\''; /* Open Quote */ CVT_APPEND_CHAR('\''); /* Open Quote */
mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used); mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
npos += convert_to_pgbinary(buf, &new_statement[npos], used); CVT_APPEND_BINARY(buf, used);
new_statement[npos++] = '\''; /* Close Quote */ CVT_APPEND_CHAR('\''); /* Close Quote */
break; break;
...@@ -1194,8 +1459,7 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1194,8 +1459,7 @@ copy_statement_with_parameters(StatementClass *stmt)
* the large object * the large object
*/ */
sprintf(param_string, "'%d'", lobj_oid); sprintf(param_string, "'%d'", lobj_oid);
strcpy(&new_statement[npos], param_string); CVT_APPEND_STR(param_string);
npos += strlen(param_string);
break; break;
...@@ -1209,16 +1473,14 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1209,16 +1473,14 @@ copy_statement_with_parameters(StatementClass *stmt)
if (buf) if (buf)
my_strcpy(param_string, sizeof(param_string), buf, used); my_strcpy(param_string, sizeof(param_string), buf, used);
sprintf(tmp, "'%s'::float4", param_string); sprintf(tmp, "'%s'::float4", param_string);
strcpy(&new_statement[npos], tmp); CVT_APPEND_STR(tmp);
npos += strlen(tmp);
break; break;
case SQL_FLOAT: case SQL_FLOAT:
case SQL_DOUBLE: case SQL_DOUBLE:
if (buf) if (buf)
my_strcpy(param_string, sizeof(param_string), buf, used); my_strcpy(param_string, sizeof(param_string), buf, used);
sprintf(tmp, "'%s'::float8", param_string); sprintf(tmp, "'%s'::float8", param_string);
strcpy(&new_statement[npos], tmp); CVT_APPEND_STR(tmp);
npos += strlen(tmp);
break; break;
case SQL_NUMERIC: case SQL_NUMERIC:
if (buf) if (buf)
...@@ -1231,33 +1493,30 @@ copy_statement_with_parameters(StatementClass *stmt) ...@@ -1231,33 +1493,30 @@ copy_statement_with_parameters(StatementClass *stmt)
} }
else else
sprintf(cbuf, "'%s'::numeric", param_string); sprintf(cbuf, "'%s'::numeric", param_string);
my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos - 1, cbuf, strlen(cbuf)); CVT_APPEND_STR(cbuf);
npos += strlen(&new_statement[npos]);
break; break;
default: /* a numeric type or SQL_BIT */ default: /* a numeric type or SQL_BIT */
if (param_sqltype == SQL_BIT) if (param_sqltype == SQL_BIT)
new_statement[npos++] = '\''; /* Open Quote */ CVT_APPEND_CHAR('\''); /* Open Quote */
if (buf) if (buf)
{ {
my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos, buf, used); CVT_APPEND_DATA(buf, used);
npos += strlen(&new_statement[npos]);
} }
else else
{ {
strcpy(&new_statement[npos], param_string); CVT_APPEND_STR(param_string);
npos += strlen(param_string);
} }
if (param_sqltype == SQL_BIT) if (param_sqltype == SQL_BIT)
new_statement[npos++] = '\''; /* Close Quote */ CVT_APPEND_CHAR('\''); /* Close Quote */
break; break;
} }
} /* end, for */ } /* end, for */
/* make sure new_statement is always null-terminated */ /* make sure new_statement is always null-terminated */
new_statement[npos] = '\0'; CVT_TERMINATE
if (stmt->hdbc->DriverToDataSource != NULL) if (stmt->hdbc->DriverToDataSource != NULL)
{ {
...@@ -1458,29 +1717,47 @@ parse_datetime(char *buf, SIMPLE_TIME *st) ...@@ -1458,29 +1717,47 @@ parse_datetime(char *buf, SIMPLE_TIME *st)
/* Change linefeed to carriage-return/linefeed */ /* Change linefeed to carriage-return/linefeed */
int int
convert_linefeeds(char *si, char *dst, size_t max) convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
{ {
size_t i = 0, size_t i = 0,
out = 0; out = 0;
for (i = 0; i < strlen(si) && out < max - 1; i++) if (max == 0)
max = 0xffffffff;
*changed = FALSE;
for (i = 0; si[i] && out < max - 1; i++)
{ {
if (si[i] == '\n') if (si[i] == '\n')
{ {
/* Only add the carriage-return if needed */ /* Only add the carriage-return if needed */
if (i > 0 && si[i - 1] == '\r') if (i > 0 && si[i - 1] == '\r')
{ {
dst[out++] = si[i]; if (dst)
dst[out++] = si[i];
else
out++;
continue; continue;
} }
*changed = TRUE;
dst[out++] = '\r'; if (dst)
dst[out++] = '\n'; {
dst[out++] = '\r';
dst[out++] = '\n';
}
else
out += 2;
} }
else else
dst[out++] = si[i]; {
if (dst)
dst[out++] = si[i];
else
out++;
}
} }
dst[out] = '\0'; if (dst)
dst[out] = '\0';
return out; return out;
} }
...@@ -1489,45 +1766,51 @@ convert_linefeeds(char *si, char *dst, size_t max) ...@@ -1489,45 +1766,51 @@ convert_linefeeds(char *si, char *dst, size_t max)
* Change carriage-return/linefeed to just linefeed * Change carriage-return/linefeed to just linefeed
* Plus, escape any special characters. * Plus, escape any special characters.
*/ */
char * int
convert_special_chars(char *si, char *dst, int used) convert_special_chars(char *si, char *dst, int used)
{ {
size_t i = 0, size_t i = 0,
out = 0, out = 0,
max; max;
static char sout[TEXT_FIELD_SIZE + 5]; char *p = NULL;
char *p;
if (dst)
p = dst;
else
p = sout;
p[0] = '\0';
if (used == SQL_NTS) if (used == SQL_NTS)
max = strlen(si); max = strlen(si);
else else
max = used; max = used;
if (dst)
{
p = dst;
p[0] = '\0';
}
#ifdef MULTIBYTE #ifdef MULTIBYTE
multibyte_init(); multibyte_init();
#endif #endif
for (i = 0; i < max; i++) for (i = 0; i < max; i++)
{ {
if (si[i] == '\r' && i + 1 < strlen(si) && si[i + 1] == '\n') if (si[i] == '\r' && si[i + 1] == '\n')
continue; continue;
#ifdef MULTIBYTE #ifdef MULTIBYTE
else if (multibyte_char_check(si[i]) == 0 && (si[i] == '\'' || si[i] == '\\')) else if (multibyte_char_check(si[i]) == 0 && (si[i] == '\'' || si[i] == '\\'))
#else #else
else if (si[i] == '\'' || si[i] == '\\') else if (si[i] == '\'' || si[i] == '\\')
#endif #endif
p[out++] = '\\'; {
if (p)
p[out++] = si[i]; p[out++] = '\\';
else
out++;
}
if (p)
p[out++] = si[i];
else
out++;
} }
p[out] = '\0'; if (p)
return p; p[out] = '\0';
return out;
} }
...@@ -1583,11 +1866,11 @@ conv_from_hex(unsigned char *s) ...@@ -1583,11 +1866,11 @@ conv_from_hex(unsigned char *s)
int int
convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax) convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax)
{ {
size_t i; size_t i, ilen = strlen(value);
int o = 0; int o = 0;
for (i = 0; i < strlen(value);) for (i = 0; i < ilen;)
{ {
if (value[i] == '\\') if (value[i] == '\\')
{ {
...@@ -1654,10 +1937,10 @@ convert_to_pgbinary(unsigned char *in, char *out, int len) ...@@ -1654,10 +1937,10 @@ convert_to_pgbinary(unsigned char *in, char *out, int len)
void void
encode(char *in, char *out) encode(char *in, char *out)
{ {
unsigned int i, unsigned int i, ilen = strlen(in),
o = 0; o = 0;
for (i = 0; i < strlen(in); i++) for (i = 0; i < ilen; i++)
{ {
if (in[i] == '+') if (in[i] == '+')
{ {
...@@ -1681,10 +1964,10 @@ encode(char *in, char *out) ...@@ -1681,10 +1964,10 @@ encode(char *in, char *out)
void void
decode(char *in, char *out) decode(char *in, char *out)
{ {
unsigned int i, unsigned int i, ilen = strlen(in),
o = 0; o = 0;
for (i = 0; i < strlen(in); i++) for (i = 0; i < ilen; i++)
{ {
if (in[i] == '+') if (in[i] == '+')
out[o++] = ' '; out[o++] = ' ';
......
...@@ -37,8 +37,8 @@ int copy_statement_with_parameters(StatementClass *stmt); ...@@ -37,8 +37,8 @@ int copy_statement_with_parameters(StatementClass *stmt);
char *convert_escape(char *value); char *convert_escape(char *value);
char *convert_money(char *s); char *convert_money(char *s);
char parse_datetime(char *buf, SIMPLE_TIME *st); char parse_datetime(char *buf, SIMPLE_TIME *st);
int convert_linefeeds(char *s, char *dst, size_t max); int convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed);
char *convert_special_chars(char *si, char *dst, int used); int convert_special_chars(char *si, char *dst, int used);
int convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax); int convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax);
int convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax); int convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax);
......
...@@ -379,16 +379,7 @@ SQLGetInfo( ...@@ -379,16 +379,7 @@ SQLGetInfo(
case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */ case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */
/* maybe this should be 0? */ /* maybe this should be 0? */
len = 4; len = 4;
/* Long Queries in 7.0+ */ value = CC_get_max_query_len(conn);
if (PG_VERSION_GE(conn, 7.0))
value = MAX_STATEMENT_LEN;
/* Prior to 7.0 we used 2*BLCKSZ */
else if (PG_VERSION_GE(conn, 6.5))
value = (2 * BLCKSZ);
else
/* Prior to 6.5 we used BLCKSZ */
value = BLCKSZ;
break; break;
case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */ case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
......
...@@ -503,6 +503,13 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si ...@@ -503,6 +503,13 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
* Static Precision (i.e., the Maximum Precision of the datatype) This * Static Precision (i.e., the Maximum Precision of the datatype) This
* has nothing to do with a result set. * has nothing to do with a result set.
*/ */
if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */
{
if (PG_VERSION_GE(SC_get_conn(stmt), 7.1))
maxsize = 0;
else
maxsize = TEXT_FIELD_SIZE;
}
if (col < 0) if (col < 0)
return maxsize; return maxsize;
......
...@@ -131,6 +131,7 @@ SQLAllocStmt(HDBC hdbc, ...@@ -131,6 +131,7 @@ SQLAllocStmt(HDBC hdbc,
/* Copy default statement options based from Connection options */ /* Copy default statement options based from Connection options */
stmt->options = conn->stmtOptions; stmt->options = conn->stmtOptions;
stmt->stmt_size_limit = CC_get_max_query_len(conn);
/* Save the handle for later */ /* Save the handle for later */
stmt->phstmt = phstmt; stmt->phstmt = phstmt;
...@@ -249,7 +250,8 @@ SC_Constructor(void) ...@@ -249,7 +250,8 @@ SC_Constructor(void)
rv->errormsg_created = FALSE; rv->errormsg_created = FALSE;
rv->statement = NULL; rv->statement = NULL;
rv->stmt_with_params[0] = '\0'; rv->stmt_with_params = NULL;
rv->stmt_size_limit = -1;
rv->statement_type = STMT_TYPE_UNKNOWN; rv->statement_type = STMT_TYPE_UNKNOWN;
rv->bindings = NULL; rv->bindings = NULL;
...@@ -313,6 +315,11 @@ SC_Destructor(StatementClass *self) ...@@ -313,6 +315,11 @@ SC_Destructor(StatementClass *self)
if (self->statement) if (self->statement)
free(self->statement); free(self->statement);
if (self->stmt_with_params)
{
free(self->stmt_with_params);
self->stmt_with_params = NULL;
}
SC_free_params(self, STMT_FREE_PARAMS_ALL); SC_free_params(self, STMT_FREE_PARAMS_ALL);
......
...@@ -210,9 +210,10 @@ struct StatementClass_ ...@@ -210,9 +210,10 @@ struct StatementClass_
char cursor_name[MAX_CURSOR_LEN + 1]; char cursor_name[MAX_CURSOR_LEN + 1];
char stmt_with_params[STD_STATEMENT_LEN]; /* statement after char *stmt_with_params; /* statement after
* parameter * parameter
* substitution */ * substitution */
int stmt_size_limit;
char pre_executing; /* This statement is prematurely executing */ char pre_executing; /* This statement is prematurely executing */
char inaccurate_result; /* Current status is PREMATURE but char inaccurate_result; /* Current status is PREMATURE but
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment