summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/convert.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/odbc/convert.c')
-rw-r--r--src/interfaces/odbc/convert.c150
1 files changed, 115 insertions, 35 deletions
diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c
index 4291e36c34..a38ffd1de8 100644
--- a/src/interfaces/odbc/convert.c
+++ b/src/interfaces/odbc/convert.c
@@ -335,12 +335,15 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
int bind_row = stmt->bind_row;
int bind_size = stmt->options.bind_size;
int result = COPY_OK;
- BOOL changed;
+ BOOL changed, true_is_minus1 = FALSE;
const char *neut_str = value;
char midtemp[2][32];
int mtemp_cnt = 0;
static BindInfoClass sbic;
BindInfoClass *pbic;
+#ifdef UNICODE_SUPPORT
+ BOOL wchanged = FALSE;
+#endif /* UNICODE_SUPPORT */
if (stmt->current_col >= 0)
{
@@ -474,15 +477,23 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
char *s;
s = midtemp[mtemp_cnt];
- strcpy(s, (char *) value);
- if (s[0] == 'f' || s[0] == 'F' || s[0] == 'n' || s[0] == 'N' || s[0] == '0')
- s[0] = '0';
- else
- s[0] = '1';
- s[1] = '\0';
+ switch (((char *)value)[0])
+ {
+ case 'f':
+ case 'F':
+ case 'n':
+ case 'N':
+ case '0':
+ strcpy(s, "0");
+ break;
+ default:
+ if (true_is_minus1)
+ strcpy(s, "-1");
+ else
+ strcpy(s, "1");
+ }
neut_str = midtemp[mtemp_cnt];
mtemp_cnt++;
-
}
break;
@@ -567,7 +578,11 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
rgbValueBindRow = (char *) rgbValue + rgbValueOffset;
+#ifdef UNICODE_SUPPORT
+ if (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR)
+#else
if (fCType == SQL_C_CHAR)
+#endif /* UNICODE_SUPPORT */
{
/* Special character formatting as required */
@@ -599,7 +614,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
break;
case PG_TYPE_BOOL:
- len = 1;
+ len = strlen(neut_str);
if (cbValueMax > len)
{
strcpy(rgbValueBindRow, neut_str);
@@ -637,8 +652,18 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
pbic = &stmt->bindings[stmt->current_col];
if (pbic->data_left < 0)
{
+ BOOL lf_conv = SC_get_conn(stmt)->connInfo.lf_conversion;
+#ifdef UNICODE_SUPPORT
+ if (fCType == SQL_C_WCHAR)
+ {
+ len = utf8_to_ucs2(neut_str, -1, NULL, 0);
+ len *= 2;
+ wchanged = changed = TRUE;
+ }
+ else
+#endif /* UNICODE_SUPPORT */
/* convert linefeeds to carriage-return/linefeed */
- len = convert_linefeeds(neut_str, NULL, 0, &changed);
+ len = convert_linefeeds(neut_str, NULL, 0, lf_conv, &changed);
if (cbValueMax == 0) /* just returns length
* info */
{
@@ -654,7 +679,14 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1);
pbic->ttlbuflen = len + 1;
}
- convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, &changed);
+#ifdef UNICODE_SUPPORT
+ if (fCType == SQL_C_WCHAR)
+ {
+ utf8_to_ucs2(neut_str, -1, (SQLWCHAR *) pbic->ttlbuf, len / 2);
+ }
+ else
+#endif /* UNICODE_SUPPORT */
+ convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, lf_conv, &changed);
ptr = pbic->ttlbuf;
}
else
@@ -715,7 +747,25 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
break;
}
-
+#ifdef UNICODE_SUPPORT
+ if (SQL_C_WCHAR == fCType && ! wchanged)
+ {
+ if (cbValueMax > 2 * len)
+ {
+ char *str = strdup(rgbValueBindRow);
+ UInt4 ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / 2);
+ if (cbValueMax < 2 * (SDWORD) ucount)
+ result = COPY_RESULT_TRUNCATED;
+ len = ucount * 2;
+ free(str);
+ }
+ else
+ {
+ len *= 2;
+ result = COPY_RESULT_TRUNCATED;
+ }
+ }
+#endif /* UNICODE_SUPPORT */
}
else
@@ -1107,11 +1157,11 @@ do { \
*/
#define CVT_SPECIAL_CHARS(buf, used) \
do { \
- int cnvlen = convert_special_chars(buf, NULL, used); \
+ int cnvlen = convert_special_chars(buf, NULL, used, lf_conv, conn->ccsc); \
unsigned int newlimit = npos + cnvlen; \
\
ENLARGE_NEWSTATEMENT(newlimit); \
- convert_special_chars(buf, &new_statement[npos], used); \
+ convert_special_chars(buf, &new_statement[npos], used, lf_conv, conn->ccsc); \
npos += cnvlen; \
} while (0)
@@ -1181,9 +1231,9 @@ table_for_update(const char *stmt, int *endpos)
}
#ifdef MULTIBYTE
-#define my_strchr(s1,c1) multibyte_strchr(s1,c1)
+#define my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
#else
-#define my_strchr(s1,c1) strchr(s1,c1)
+#define my_strchr(conn, s1,c1) strchr(s1,c1)
#endif
/*
* This function inserts parameters into an SQL statements.
@@ -1213,8 +1263,7 @@ copy_statement_with_parameters(StatementClass *stmt)
time_t t = time(NULL);
struct tm *tim;
SDWORD used;
- char *buffer,
- *buf;
+ char *buffer, *buf, *allocbuf;
BOOL in_quote = FALSE,
in_dquote = FALSE,
in_escape = FALSE;
@@ -1234,6 +1283,10 @@ copy_statement_with_parameters(StatementClass *stmt)
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;
+ BOOL lf_conv = ci->lf_conversion;
+#ifdef MULTIBYTE
+ encoded_str encstr;
+#endif /* MULTIBYTE */
#ifdef DRIVER_CURSOR_IMPLEMENT
BOOL search_from_pos = FALSE;
@@ -1311,14 +1364,14 @@ copy_statement_with_parameters(StatementClass *stmt)
}
param_number = -1;
#ifdef MULTIBYTE
- multibyte_init();
+ make_encoded_str(&encstr, conn, old_statement);
#endif
for (opos = 0; opos < oldstmtlen; opos++)
{
- oldchar = old_statement[opos];
#ifdef MULTIBYTE
- if (multibyte_char_check(oldchar) != 0)
+ oldchar = encoded_byte_check(&encstr, opos);
+ if (ENCODE_STATUS(encstr) != 0)
{
CVT_APPEND_CHAR(oldchar);
continue;
@@ -1327,6 +1380,8 @@ copy_statement_with_parameters(StatementClass *stmt)
/*
* From here we are guaranteed to handle a 1-byte character.
*/
+#else
+ oldchar = old_statement[opos];
#endif
if (in_escape) /* escape check */
@@ -1352,7 +1407,7 @@ copy_statement_with_parameters(StatementClass *stmt)
* nor a double quote.
*/
/* Squeeze carriage-return/linefeed pairs to linefeed only */
- else if (oldchar == '\r' && opos + 1 < oldstmtlen &&
+ else if (lf_conv && oldchar == '\r' && opos + 1 < oldstmtlen &&
old_statement[opos + 1] == '\n')
continue;
@@ -1390,11 +1445,12 @@ copy_statement_with_parameters(StatementClass *stmt)
}
opos += lit_call_len;
CVT_APPEND_STR("SELECT ");
- if (my_strchr(&old_statement[opos], '('))
+ if (my_strchr(conn, &old_statement[opos], '('))
proc_no_param = FALSE;
continue;
}
- if (convert_escape(begin, stmt, &npos, &new_stsize, &end) != CONVERT_ESCAPE_OK)
+ if (convert_escape(begin, stmt, &npos, &new_stsize, &end
+) != CONVERT_ESCAPE_OK)
{
stmt->errormsg = "ODBC escape convert error";
stmt->errornumber = STMT_EXEC_ERROR;
@@ -1585,7 +1641,7 @@ copy_statement_with_parameters(StatementClass *stmt)
if (param_ctype == SQL_C_DEFAULT)
param_ctype = sqltype_to_default_ctype(param_sqltype);
- buf = NULL;
+ allocbuf = buf = NULL;
param_string[0] = '\0';
cbuf[0] = '\0';
@@ -1597,6 +1653,13 @@ copy_statement_with_parameters(StatementClass *stmt)
buf = buffer;
break;
+#ifdef UNICODE_SUPPORT
+ case SQL_C_WCHAR:
+ buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used / 2, &used);
+ used *= 2;
+ break;
+#endif /* UNICODE_SUPPORT */
+
case SQL_C_DOUBLE:
sprintf(param_string, "%.15g",
*((SDOUBLE *) buffer));
@@ -1729,6 +1792,11 @@ copy_statement_with_parameters(StatementClass *stmt)
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
+#ifdef UNICODE_SUPPORT
+ case SQL_WCHAR:
+ case SQL_WVARCHAR:
+ case SQL_WLONGVARCHAR:
+#endif /* UNICODE_SUPPORT */
CVT_APPEND_CHAR('\''); /* Open Quote */
@@ -1801,7 +1869,7 @@ copy_statement_with_parameters(StatementClass *stmt)
tmp[0] = '\'';
/* Time zone stuff is unreliable */
stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2));
- strcat(tmp, "'");
+ strcat(tmp, "'::timestamp");
CVT_APPEND_STR(tmp);
@@ -1942,6 +2010,10 @@ copy_statement_with_parameters(StatementClass *stmt)
break;
}
+#ifdef UNICODE_SUPPORT
+ if (allocbuf)
+ free(allocbuf);
+#endif /* UNICODE_SUPPORT */
} /* end, for */
/* make sure new_statement is always null-terminated */
@@ -2032,7 +2104,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value,
while ((*valptr != '\0') && isspace((unsigned char) *valptr))
valptr++;
- if (end = my_strchr(valptr, '}'), NULL == end)
+ if (end = my_strchr(conn, valptr, '}'), NULL == end)
{
mylog("%s couldn't find the ending }\n",func);
return CONVERT_ESCAPE_ERROR;
@@ -2226,13 +2298,16 @@ int processParameters(const ConnectionClass *conn, const char *value,
const char *valptr;
char buf[1024];
BOOL in_quote, in_dquote, in_escape, leadingSpace;
+#ifdef MULTIBYTE
+ encoded_str encstr;
+#endif /* MULTIBYTE */
buf[sizeof(buf)-1] = '\0';
innerParenthesis = 0;
in_quote = in_dquote = in_escape = leadingSpace = FALSE;
param_count = 0;
#ifdef MULTIBYTE
- multibyte_init();
+ make_encoded_str(&encstr, conn, value);
#endif /* MULTIBYTE */
/* begin with outer '(' */
for (stop = FALSE, valptr = value, ipos = count = 0; *valptr != '\0'; ipos++, valptr++)
@@ -2250,7 +2325,8 @@ int processParameters(const ConnectionClass *conn, const char *value,
return CONVERT_ESCAPE_OVERFLOW;
}
#ifdef MULTIBYTE
- if (multibyte_char_check(*valptr) != 0)
+ encoded_byte_check(&encstr, ipos);
+ if (ENCODE_STATUS(encstr) != 0)
{
result[count++] = *valptr;
continue;
@@ -2468,7 +2544,7 @@ parse_datetime(char *buf, SIMPLE_TIME *st)
/* Change linefeed to carriage-return/linefeed */
int
-convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
+convert_linefeeds(const char *si, char *dst, size_t max, BOOL convlf, BOOL *changed)
{
size_t i = 0,
out = 0;
@@ -2478,7 +2554,7 @@ convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
*changed = FALSE;
for (i = 0; si[i] && out < max - 1; i++)
{
- if (si[i] == '\n')
+ if (convlf && si[i] == '\n')
{
/* Only add the carriage-return if needed */
if (i > 0 && si[i - 1] == '\r')
@@ -2518,12 +2594,15 @@ convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
* Plus, escape any special characters.
*/
int
-convert_special_chars(const char *si, char *dst, int used)
+convert_special_chars(const char *si, char *dst, int used, BOOL convlf, int ccsc)
{
size_t i = 0,
out = 0,
max;
char *p = NULL;
+#ifdef MULTIBYTE
+ encoded_str encstr;
+#endif
if (used == SQL_NTS)
@@ -2536,13 +2615,14 @@ convert_special_chars(const char *si, char *dst, int used)
p[0] = '\0';
}
#ifdef MULTIBYTE
- multibyte_init();
+ encoded_str_constr(&encstr, ccsc, si);
#endif
for (i = 0; i < max && si[i]; i++)
{
#ifdef MULTIBYTE
- if (multibyte_char_check(si[i]) != 0)
+ encoded_nextchar(&encstr);
+ if (ENCODE_STATUS(encstr) != 0)
{
if (p)
p[out] = si[i];
@@ -2550,7 +2630,7 @@ convert_special_chars(const char *si, char *dst, int used)
continue;
}
#endif
- if (si[i] == '\r' && si[i + 1] == '\n')
+ if (convlf && si[i] == '\r' && si[i + 1] == '\n')
continue;
else if (si[i] == '\'' || si[i] == '\\')
{