2 * Description: This module contains routines related to
3 * converting parameters and columns into requested data types.
4 * Parameters are converted from their SQL_C data types into
5 * the appropriate postgres type. Columns are converted from
6 * their postgres type (SQL type) into the appropriate SQL_C
9 /* Multibyte support Eiji Tokuya 2001-03-15 */
20 #include "multibyte.h"
28 #include "statement.h"
32 #include "connection.h"
34 #include "pgapifunc.h"
36 #if defined(UNICODE_SUPPORT) && defined(WIN32)
37 #define WIN_UNICODE_SUPPORT
40 CSTR NAN_STRING
= "NaN";
41 CSTR INFINITY_STRING
= "Infinity";
42 CSTR MINFINITY_STRING
= "-Infinity";
45 #define TIMEZONE_GLOBAL _timezone
46 #elif defined(WIN32) || defined(HAVE_INT_TIMEZONE)
47 #define TIMEZONE_GLOBAL timezone
51 static int conv_from_octal(const UCHAR
* s
);
52 static SQLLEN
pg_bin2hex(UCHAR
* src
, UCHAR
* dst
, SQLLEN length
);
55 * A Guide for date/time/timestamp conversions
57 * field_type fCType Output
58 * ---------- ------ ----------
59 * PG_TYPE_DATE SQL_C_DEFAULT SQL_C_DATE
60 * PG_TYPE_DATE SQL_C_DATE SQL_C_DATE
61 * PG_TYPE_DATE SQL_C_TIMESTAMP SQL_C_TIMESTAMP (time = 0 (midnight))
62 * PG_TYPE_TIME SQL_C_DEFAULT SQL_C_TIME
63 * PG_TYPE_TIME SQL_C_TIME SQL_C_TIME
64 * PG_TYPE_TIME SQL_C_TIMESTAMP SQL_C_TIMESTAMP (date = current date)
65 * PG_TYPE_ABSTIME SQL_C_DEFAULT SQL_C_TIMESTAMP
66 * PG_TYPE_ABSTIME SQL_C_DATE SQL_C_DATE (time is truncated)
67 * PG_TYPE_ABSTIME SQL_C_TIME SQL_C_TIME (date is truncated)
68 * PG_TYPE_ABSTIME SQL_C_TIMESTAMP SQL_C_TIMESTAMP
74 * Macros for unsigned long handling.
78 #elif defined(HAVE_STRTOUL)
79 #define ATOI32U(val) strtoul(val, NULL, 10)
80 #else /* HAVE_STRTOUL */
85 * Macros for BIGINT handling.
89 #define ATOI64 _atoi64
90 #define ATOI64U _atoi64
91 #define FORMATI64 "%I64d"
92 #define FORMATI64U "%I64u"
93 #elif (SIZEOF_LONG == 8)
94 #define ATOI64(val) strtol(val, NULL, 10)
95 #define ATOI64U(val) strtoul(val, NULL, 10)
96 #define FORMATI64 "%ld"
97 #define FORMATI64U "%lu"
99 #define FORMATI64 "%lld"
100 #define FORMATI64U "%llu"
101 #if defined(HAVE_STRTOLL)
102 #define ATOI64(val) strtoll(val, NULL, 10)
103 #define ATOI64U(val) strtoull(val, NULL, 10)
105 static ODBCINT64
ATOI64(const char *val
)
108 sscanf(val
, "%lld", &ll
);
111 static unsigned ODBCINT64
ATOI64U(const char *val
)
113 unsigned ODBCINT64 ll
;
114 sscanf(val
, "%llu", &ll
);
117 #endif /* HAVE_STRTOLL */
119 #endif /* ODBCINT64 */
122 * TIMESTAMP <-----> SIMPLE_TIME
123 * precision support since 7.2.
124 * time zone support is unavailable(the stuff is unreliable)
126 // FIXME: Anyone calling this function is probably doing something undesirable
128 stime2timestamp(const SIMPLE_TIME
* st
, char *str
, BOOL bZone
,
131 char precstr
[16], zonestr
[16];
135 if (st
->infinity
> 0)
137 strcpy(str
, INFINITY_STRING
);
139 } else if (st
->infinity
< 0)
141 strcpy(str
, MINFINITY_STRING
);
144 if (precision
&& st
->fr
)
146 sprintf(precstr
, ".%09d", st
->fr
);
147 for (i
= 9; i
> 0; i
--)
149 if (precstr
[i
] != '0')
155 #ifdef TIMEZONE_GLOBAL
156 if (bZone
&& tzname
[0] && tzname
[0][0] && st
->y
>= 1970)
162 zoneint
= TIMEZONE_GLOBAL
;
163 if (daylight
&& st
->y
>= 1900)
165 tm
.tm_year
= st
->y
- 1900;
166 tm
.tm_mon
= st
->m
- 1;
173 if (time0
>= 0 && tm
.tm_isdst
> 0)
177 sprintf(zonestr
, "-%02d", (int) zoneint
/ 3600);
179 sprintf(zonestr
, "+%02d", -(int) zoneint
/ 3600);
181 #endif /* TIMEZONE_GLOBAL */
183 sprintf(str
, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s BC", -st
->y
,
184 st
->m
, st
->d
, st
->hh
, st
->mm
, st
->ss
, precstr
, zonestr
);
186 sprintf(str
, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s", st
->y
, st
->m
,
187 st
->d
, st
->hh
, st
->mm
, st
->ss
, precstr
, zonestr
);
191 /* This is called by SQLFetch() */
193 copy_and_convert_field_bindinfo(StatementClass
* stmt
, OID field_type
,
194 void *value
, int col
)
196 ARDFields
*opts
= SC_get_ARDF(stmt
);
197 BindInfoClass
*bic
= &(opts
->bindings
[col
]);
198 SQLULEN offset
= opts
->row_offset_ptr
? *opts
->row_offset_ptr
: 0;
200 SC_set_current_col(stmt
, -1);
201 return copy_and_convert_field(stmt
, field_type
, value
,
203 (PTR
) (bic
->buffer
+ offset
),
204 bic
->buflen
, LENADDR_SHIFT(bic
->used
,
206 LENADDR_SHIFT(bic
->indicator
,
210 static double get_double_value(const char *str
)
212 if (stricmp(str
, NAN_STRING
) == 0)
214 else if (stricmp(str
, INFINITY_STRING
) == 0)
216 else if (stricmp(str
, MINFINITY_STRING
) == 0)
221 /* This is called by SQLGetData() */
223 copy_and_convert_field(StatementClass
* stmt
, OID field_type
,
224 void *valuei
, SQLSMALLINT fCType
, PTR rgbValue
,
225 SQLLEN cbValueMax
, SQLLEN
* pcbValue
,
228 CSTR func
= "copy_and_convert_field";
229 const char *value
= (const char *)valuei
;
230 ARDFields
*opts
= SC_get_ARDF(stmt
);
231 GetDataInfo
*gdata
= SC_get_GDTI(stmt
);
232 SQLLEN len
= 0, copy_len
= 0, needbuflen
= 0;
233 SIMPLE_TIME std_time
;
234 time_t stmt_t
= SC_get_time(stmt
);
236 SQLLEN pcbValueOffset
, rgbValueOffset
;
237 char *rgbValueBindRow
= NULL
;
238 SQLLEN
*pcbValueBindRow
= NULL
, *pIndicatorBindRow
= NULL
;
240 SQLSETPOSIROW bind_row
= stmt
->bind_row
;
241 int bind_size
= opts
->bind_size
;
242 int result
= COPY_OK
;
243 ConnectionClass
*conn
= SC_get_conn(stmt
);
244 BOOL changed
, true_is_minus1
= FALSE
;
245 BOOL text_handling
, localize_needed
;
246 const char *neut_str
= value
;
250 #ifdef UNICODE_SUPPORT
251 BOOL wconverted
= FALSE
;
252 #endif /* UNICODE_SUPPORT */
253 #ifdef WIN_UNICODE_SUPPORT
254 SQLWCHAR
*allocbuf
= NULL
;
256 #endif /* WIN_UNICODE_SUPPORT */
259 #endif /* HAVE_LOCALE_H */
261 if (stmt
->current_col
>= 0)
263 if (stmt
->current_col
>= opts
->allocated
)
267 if (gdata
->allocated
!= opts
->allocated
)
268 extend_getdata_info(gdata
, opts
->allocated
, TRUE
);
269 pgdc
= &gdata
->gdata
[stmt
->current_col
];
270 if (pgdc
->data_left
== -2)
271 pgdc
->data_left
= (cbValueMax
> 0) ? 0 : -1; /* This seems to be *
273 if (pgdc
->data_left
== 0)
275 if (pgdc
->ttlbuf
!= NULL
)
281 pgdc
->data_left
= -2; /* needed by ADO ? */
282 return COPY_NO_DATA_FOUND
;
286 * rgbValueOffset is *ONLY* for character and binary data.
287 * pcbValueOffset is for computing any pcbValue location
292 pcbValueOffset
= rgbValueOffset
= (bind_size
* bind_row
);
295 pcbValueOffset
= bind_row
* sizeof(SQLLEN
);
296 rgbValueOffset
= bind_row
* cbValueMax
;
299 * The following is applicable in case bind_size > 0
300 * or the fCType is of variable length.
303 rgbValueBindRow
= (char *) rgbValue
+ rgbValueOffset
;
305 pcbValueBindRow
= LENADDR_SHIFT(pcbValue
, pcbValueOffset
);
308 pIndicatorBindRow
= LENADDR_SHIFT(pIndicator
, pcbValueOffset
);
309 *pIndicatorBindRow
= 0;
312 memset(&std_time
, 0, sizeof(SIMPLE_TIME
));
314 /* Initialize current date */
317 tim
= gmtime_r(&stmt_t
, &tm
);
319 tim
= gmtime(&stmt_t
);
320 #endif /* HAVE_GMTIME_R */
321 std_time
.m
= tim
->tm_mon
+ 1;
322 std_time
.d
= tim
->tm_mday
;
323 std_time
.y
= tim
->tm_year
+ 1900;
326 ("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n",
327 field_type
, fCType
, (value
== NULL
) ? "<NULL>" : value
,
332 mylog("null_cvt_date_string=%d\n",
333 conn
->connInfo
.cvt_null_date_string
);
334 /* a speicial handling for FOXPRO NULL -> NULL_STRING */
335 if (conn
->connInfo
.cvt_null_date_string
> 0 &&
336 PG_TYPE_DATE
== field_type
&&
337 (SQL_C_CHAR
== fCType
||
338 SQL_C_TYPE_DATE
== fCType
|| SQL_C_DEFAULT
== fCType
))
341 *pcbValueBindRow
= 0;
345 if (rgbValueBindRow
&& cbValueMax
> 0)
346 rgbValueBindRow
= '\0';
348 result
= COPY_RESULT_TRUNCATED
;
350 case SQL_C_TYPE_DATE
:
353 && cbValueMax
>= sizeof(DATE_STRUCT
))
355 memset(rgbValueBindRow
, 0, cbValueMax
);
357 *pcbValueBindRow
= sizeof(DATE_STRUCT
);
359 result
= COPY_RESULT_TRUNCATED
;
361 #ifdef UNICODE_SUPPORT
363 if (rgbValueBindRow
&& cbValueMax
>= WCLEN
)
364 memset(rgbValueBindRow
, 0, WCLEN
);
366 result
= COPY_RESULT_TRUNCATED
;
368 #endif /* UNICODE_SUPPORT */
373 * handle a null just by returning SQL_NULL_DATA in pcbValue, and
374 * doing nothing to the buffer.
378 *pIndicatorBindRow
= SQL_NULL_DATA
;
382 SC_set_error(stmt
, STMT_RETURN_NULL_WITHOUT_INDICATOR
,
383 "StrLen_or_IndPtr was a null pointer and NULL data was retrieved",
389 if (stmt
->hdbc
->DataSourceToDriver
!= NULL
)
391 size_t length
= strlen(value
);
393 stmt
->hdbc
->DataSourceToDriver(stmt
->hdbc
->translation_option
,
395 (SDWORD
) length
, valuei
,
396 (SDWORD
) length
, NULL
, NULL
, 0,
401 * First convert any specific postgres types into more useable data.
403 * NOTE: Conversions from PG char/varchar of a date/time/timestamp value
404 * to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
409 * $$$ need to add parsing for date/time/timestamp strings in
410 * PG_TYPE_CHAR,VARCHAR $$$
412 case VX_TYPE_DATETIME
:
416 sscanf(value
, "[%lld,%d]", &secs
, &usecs
);
418 // January 1, 1900, 00:00:00. Note: outside the range of 32-bit time_t.
419 long long sql_epoch
= -2208988800LL;
420 int seconds_per_day
= 60*60*24;
421 if (secs
>= sql_epoch
&& secs
< sql_epoch
+ seconds_per_day
)
423 // The value is a time of day for the SQL Epoch, aka a SQL time
424 // value. Fudge it to the Unix Epoch, so gmtime() can deal
425 // with it on 32-bit systems. If it was a DateTime, it was going
426 // to be wrong anyway.
430 // FIXME: This loses precision on 32-bit systems.
431 time_t secs_time_t
= (time_t)secs
;
436 if ((ptm
= gmtime_r(&secs_time_t
, &tm
)) != NULL
)
438 if ((ptm
= gmtime(&secs_time_t
)) != NULL
)
439 #endif /* HAVE_GMTIME_R */
441 std_time
.y
= ptm
->tm_year
+ 1900;
442 std_time
.m
= ptm
->tm_mon
+ 1;
443 std_time
.d
= ptm
->tm_mday
;
444 std_time
.hh
= ptm
->tm_hour
;
445 std_time
.mm
= ptm
->tm_min
;
446 std_time
.ss
= ptm
->tm_sec
;
447 // The server provides us with millionths of a second, but ODBC
449 std_time
.fr
= usecs
* 1000;
454 sscanf(value
, "%4d-%2d-%2d", &std_time
.y
, &std_time
.m
,
459 sscanf(value
, "%2d:%2d:%2d", &std_time
.hh
, &std_time
.mm
,
464 { /* change T/F to 1/0 */
467 s
= midtemp
[mtemp_cnt
];
468 switch (((char *) value
)[0])
483 neut_str
= midtemp
[mtemp_cnt
];
488 /* This is for internal use by SQLStatistics() */
489 case PG_TYPE_INT2VECTOR
:
490 if (SQL_C_DEFAULT
== fCType
)
494 /* this is an array of eight integers */
495 short *short_array
= (short *) rgbValueBindRow
, shortv
;
498 if (NULL
!= short_array
)
499 maxc
= (int) cbValueMax
/ sizeof(short);
505 if (sscanf(vp
, "%hi", &shortv
) != 1)
507 mylog(" %hi", shortv
);
508 if (0 == shortv
&& PG_VERSION_LT(conn
, 7.2))
512 short_array
[i
+ 1] = shortv
;
514 /* skip the current token */
515 while ((*vp
!= '\0') && (!isspace((UCHAR
) * vp
)))
517 /* and skip the space to the next token */
518 while ((*vp
!= '\0') && (isspace((UCHAR
) * vp
)))
523 mylog(") nval = %i\n", nval
);
525 short_array
[0] = nval
;
527 /* There is no corresponding fCType for this. */
528 len
= (nval
+ 1) * sizeof(short);
530 *pcbValueBindRow
= len
;
532 if (len
<= cbValueMax
)
533 return COPY_OK
; /* dont go any further or the data will be
536 return COPY_RESULT_TRUNCATED
;
541 * This is a large object OID, which is used to store
542 * LONGVARBINARY objects.
544 case PG_TYPE_LO_UNDEFINED
:
546 SC_set_error(stmt
, STMT_EXEC_ERROR
, "Large objects are not supported.",
555 /* Change default into something useable */
556 if (fCType
== SQL_C_DEFAULT
)
558 fCType
= pgtype_to_ctype(stmt
, field_type
);
559 if (fCType
== SQL_C_WCHAR
&& CC_default_is_c(conn
))
562 mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType
);
565 text_handling
= localize_needed
= FALSE
;
568 case INTERNAL_ASIS_TYPE
:
569 #ifdef UNICODE_SUPPORT
571 #endif /* UNICODE_SUPPORT */
573 text_handling
= TRUE
;
578 case PG_TYPE_UNKNOWN
:
580 case PG_TYPE_VARCHAR
:
582 case PG_TYPE_BPCHARARRAY
:
583 case PG_TYPE_VARCHARARRAY
:
584 case PG_TYPE_TEXTARRAY
:
585 text_handling
= TRUE
;
592 #ifdef WIN_UNICODE_SUPPORT
593 if (SQL_C_CHAR
== fCType
|| SQL_C_BINARY
== fCType
)
594 localize_needed
= TRUE
;
595 #endif /* WIN_UNICODE_SUPPORT */
600 /* Special character formatting as required */
603 * These really should return error if cbValueMax is not big
610 if (cbValueMax
> len
)
611 sprintf(rgbValueBindRow
, "%.4d-%.2d-%.2d", std_time
.y
,
612 std_time
.m
, std_time
.d
);
617 if (cbValueMax
> len
)
618 sprintf(rgbValueBindRow
, "%.2d:%.2d:%.2d", std_time
.hh
,
619 std_time
.mm
, std_time
.ss
);
622 case VX_TYPE_DATETIME
:
624 if (cbValueMax
> len
)
626 if (!std_time
.hh
&& !std_time
.mm
&&!std_time
.ss
)
627 sprintf(rgbValueBindRow
,
628 "%.4d-%.2d-%.2d", std_time
.y
,
629 std_time
.m
, std_time
.d
);
631 sprintf(rgbValueBindRow
,
632 "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", std_time
.y
,
633 std_time
.m
, std_time
.d
, std_time
.hh
,
634 std_time
.mm
, std_time
.ss
);
635 len
= strlen(rgbValueBindRow
);
640 len
= strlen(neut_str
);
641 if (cbValueMax
> len
)
643 strcpy(rgbValueBindRow
, neut_str
);
644 mylog("PG_TYPE_BOOL: rgbValueBindRow = '%s'\n",
650 * Currently, data is SILENTLY TRUNCATED for BYTEA and
651 * character data types if there is not enough room in
652 * cbValueMax because the driver can't handle multiple
653 * calls to SQLGetData for these, yet. Most likely, the
654 * buffer passed in will be big enough to handle the
655 * maximum limit of postgres, anyway.
657 * LongVarBinary types are handled correctly above, observing
658 * truncation and all that stuff since there is
659 * essentially no limit on the large object used to store
662 case PG_TYPE_BYTEA
: /* convert binary data to hex strings
663 * (i.e, 255 = "FF") */
666 if (stmt
->current_col
< 0)
668 pgdc
= &(gdata
->fdata
);
669 pgdc
->data_left
= -1;
671 pgdc
= &gdata
->gdata
[stmt
->current_col
];
672 #ifdef UNICODE_SUPPORT
673 if (fCType
== SQL_C_WCHAR
)
675 #endif /* UNICODE_SUPPORT */
676 if (pgdc
->data_left
< 0)
678 BOOL lf_conv
= conn
->connInfo
.lf_conversion
;
679 #ifdef UNICODE_SUPPORT
680 if (fCType
== SQL_C_WCHAR
)
683 utf8_to_ucs2_lf(neut_str
, SQL_NTS
, lf_conv
,
688 #endif /* UNICODE_SUPPORT */
689 if (PG_TYPE_BYTEA
== field_type
)
691 len
= convert_from_pgbinary((const UCHAR
*)neut_str
, NULL
, 0);
695 #ifdef WIN_UNICODE_SUPPORT
699 utf8_to_ucs2_lf(neut_str
, SQL_NTS
, lf_conv
,
702 (SQLWCHAR
*) malloc(WCLEN
* (wstrlen
+ 1));
704 utf8_to_ucs2_lf(neut_str
, SQL_NTS
, lf_conv
,
705 allocbuf
, wstrlen
+ 1);
707 WideCharToMultiByte(CP_ACP
, 0,
709 (int) wstrlen
, NULL
, 0,
713 #endif /* WIN_UNICODE_SUPPORT */
714 /* convert linefeeds to carriage-return/linefeed */
716 convert_linefeeds(neut_str
, NULL
, 0, lf_conv
,
718 if (cbValueMax
== 0) /* just returns length
721 result
= COPY_RESULT_TRUNCATED
;
722 #ifdef WIN_UNICODE_SUPPORT
725 #endif /* WIN_UNICODE_SUPPORT */
733 #ifdef UNICODE_SUPPORT
737 #endif /* UNICODE_SUPPORT */
743 if (changed
|| needbuflen
> cbValueMax
)
745 if (needbuflen
> (SQLLEN
) pgdc
->ttlbuflen
)
747 pgdc
->ttlbuf
= (char *)
748 realloc(pgdc
->ttlbuf
, needbuflen
);
749 pgdc
->ttlbuflen
= needbuflen
;
751 #ifdef UNICODE_SUPPORT
752 if (fCType
== SQL_C_WCHAR
)
754 utf8_to_ucs2_lf(neut_str
, SQL_NTS
, lf_conv
,
755 (SQLWCHAR
*) pgdc
->ttlbuf
,
758 #endif /* UNICODE_SUPPORT */
759 if (PG_TYPE_BYTEA
== field_type
)
762 convert_from_pgbinary((UCHAR
*)neut_str
,
763 (UCHAR
*)pgdc
->ttlbuf
,
765 pg_bin2hex((UCHAR
*)pgdc
->ttlbuf
,
766 (UCHAR
*)pgdc
->ttlbuf
, len
);
769 #ifdef WIN_UNICODE_SUPPORT
773 WideCharToMultiByte(CP_ACP
, 0, allocbuf
,
776 (int) pgdc
->ttlbuflen
,
781 #endif /* WIN_UNICODE_SUPPORT */
782 convert_linefeeds(neut_str
, pgdc
->ttlbuf
,
783 pgdc
->ttlbuflen
, lf_conv
,
786 pgdc
->ttlbufused
= len
;
799 len
= pgdc
->ttlbufused
;
802 mylog("DEFAULT: len = %d, ptr = '%.*s'\n", len
, len
, ptr
);
804 if (stmt
->current_col
>= 0)
806 if (pgdc
->data_left
> 0)
808 ptr
+= len
- pgdc
->data_left
;
809 len
= pgdc
->data_left
;
811 len
+ (pgdc
->ttlbuflen
- pgdc
->ttlbufused
);
813 pgdc
->data_left
= len
;
818 BOOL already_copied
= FALSE
;
820 if (fCType
== SQL_C_BINARY
)
821 copy_len
= (len
> cbValueMax
) ? cbValueMax
: len
;
824 (len
>= cbValueMax
) ? (cbValueMax
- 1) : len
;
825 #ifdef UNICODE_SUPPORT
826 if (fCType
== SQL_C_WCHAR
)
831 #endif /* UNICODE_SUPPORT */
837 case PG_TYPE_NUMERIC
:
843 new_string
= (char *)malloc(cbValueMax
);
845 for (i
= 0, j
= 0; ptr
[i
]; i
++)
848 strncpy(&new_string
[j
],
850 strlen(lc
->decimal_point
));
851 j
+= strlen(lc
->decimal_point
);
853 new_string
[j
++] = ptr
[i
];
854 new_string
[j
] = '\0';
855 strncpy_null(rgbValueBindRow
, new_string
,
858 already_copied
= TRUE
;
862 #endif /* HAVE_LOCALE_H */
866 memcpy(rgbValueBindRow
, ptr
, copy_len
);
867 /* Add null terminator */
868 #ifdef UNICODE_SUPPORT
869 if (fCType
== SQL_C_WCHAR
)
871 if (copy_len
+ WCLEN
<= cbValueMax
)
872 memset(rgbValueBindRow
+ copy_len
, 0,
875 #endif /* UNICODE_SUPPORT */
876 if (copy_len
< cbValueMax
)
877 rgbValueBindRow
[copy_len
] = '\0';
879 /* Adjust data_left for next time */
880 if (stmt
->current_col
>= 0)
881 pgdc
->data_left
-= copy_len
;
885 * Finally, check for truncation so that proper status can
888 if (cbValueMax
> 0 && needbuflen
> cbValueMax
)
889 result
= COPY_RESULT_TRUNCATED
;
892 if (pgdc
->ttlbuf
!= NULL
)
900 if (SQL_C_WCHAR
== fCType
)
902 (" SQL_C_WCHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n",
903 len
, cbValueMax
, rgbValueBindRow
);
904 else if (SQL_C_BINARY
== fCType
)
906 (" SQL_C_BINARY, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%.*s'\n",
907 len
, cbValueMax
, copy_len
, rgbValueBindRow
);
910 (" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n",
911 len
, cbValueMax
, rgbValueBindRow
);
914 #ifdef UNICODE_SUPPORT
915 if (SQL_C_WCHAR
== fCType
&& !wconverted
)
917 char *str
= strdup(rgbValueBindRow
);
919 utf8_to_ucs2(str
, len
, (SQLWCHAR
*) rgbValueBindRow
,
921 if (cbValueMax
< WCLEN
* ucount
)
922 result
= COPY_RESULT_TRUNCATED
;
923 len
= ucount
* WCLEN
;
926 #endif /* UNICODE_SUPPORT */
931 * for SQL_C_CHAR, it's probably ok to leave currency symbols in.
932 * But to convert to numeric types, it is necessary to get rid of
935 if (field_type
== PG_TYPE_MONEY
)
938 (neut_str
, midtemp
[mtemp_cnt
], sizeof(midtemp
[0])))
940 neut_str
= midtemp
[mtemp_cnt
];
944 qlog("couldn't convert money type to %d\n", fCType
);
945 return COPY_UNSUPPORTED_TYPE
;
952 case SQL_C_TYPE_DATE
: /* 91 */
958 ds
= (DATE_STRUCT
*) rgbValueBindRow
;
960 ds
= (DATE_STRUCT
*) rgbValue
+ bind_row
;
961 ds
->year
= std_time
.y
;
962 ds
->month
= std_time
.m
;
963 ds
->day
= std_time
.d
;
968 case SQL_C_TYPE_TIME
: /* 92 */
974 ts
= (TIME_STRUCT
*) rgbValueBindRow
;
976 ts
= (TIME_STRUCT
*) rgbValue
+ bind_row
;
977 ts
->hour
= std_time
.hh
;
978 ts
->minute
= std_time
.mm
;
979 ts
->second
= std_time
.ss
;
983 case SQL_C_TIMESTAMP
:
984 case SQL_C_TYPE_TIMESTAMP
: /* 93 */
987 TIMESTAMP_STRUCT
*ts
;
990 ts
= (TIMESTAMP_STRUCT
*) rgbValueBindRow
;
992 ts
= (TIMESTAMP_STRUCT
*) rgbValue
+ bind_row
;
993 ts
->year
= std_time
.y
;
994 ts
->month
= std_time
.m
;
995 ts
->day
= std_time
.d
;
996 ts
->hour
= std_time
.hh
;
997 ts
->minute
= std_time
.mm
;
998 ts
->second
= std_time
.ss
;
999 ts
->fraction
= std_time
.fr
;
1006 *((UCHAR
*) rgbValueBindRow
) = atoi(neut_str
);
1008 *((UCHAR
*) rgbValue
+ bind_row
) = atoi(neut_str
);
1011 * mylog("SQL_C_BIT: bind_row = %d val = %d, cb = %d,
1012 * rgb=%d\n", bind_row, atoi(neut_str), cbValueMax,
1013 * *((UCHAR *)rgbValue));
1017 case SQL_C_STINYINT
:
1021 *((SCHAR
*) rgbValueBindRow
) = atoi(neut_str
);
1023 *((SCHAR
*) rgbValue
+ bind_row
) = atoi(neut_str
);
1026 case SQL_C_UTINYINT
:
1029 *((UCHAR
*) rgbValueBindRow
) = atoi(neut_str
);
1031 *((UCHAR
*) rgbValue
+ bind_row
) = atoi(neut_str
);
1035 #ifdef HAVE_LOCALE_H
1036 saved_locale
= strdup(setlocale(LC_ALL
, NULL
));
1037 setlocale(LC_ALL
, "C");
1038 #endif /* HAVE_LOCALE_H */
1041 *((SFLOAT
*) rgbValueBindRow
) =
1042 (float) get_double_value(neut_str
);
1044 *((SFLOAT
*) rgbValue
+ bind_row
) =
1045 (float) get_double_value(neut_str
);
1046 #ifdef HAVE_LOCALE_H
1047 setlocale(LC_ALL
, saved_locale
);
1049 #endif /* HAVE_LOCALE_H */
1053 #ifdef HAVE_LOCALE_H
1054 saved_locale
= strdup(setlocale(LC_ALL
, NULL
));
1055 setlocale(LC_ALL
, "C");
1056 #endif /* HAVE_LOCALE_H */
1059 *((SDOUBLE
*) rgbValueBindRow
) =
1060 get_double_value(neut_str
);
1062 *((SDOUBLE
*) rgbValue
+ bind_row
) =
1063 get_double_value(neut_str
);
1064 #ifdef HAVE_LOCALE_H
1065 setlocale(LC_ALL
, saved_locale
);
1067 #endif /* HAVE_LOCALE_H */
1071 #ifdef HAVE_LOCALE_H
1072 /* strcpy(saved_locale, setlocale(LC_ALL, NULL));
1073 setlocale(LC_ALL, "C"); not needed currently */
1074 #endif /* HAVE_LOCALE_H */
1076 SQL_NUMERIC_STRUCT
*ns
;
1077 int i
, nlen
, bit
, hval
, tv
, dig
, sta
, olen
;
1078 char calv
[SQL_MAX_NUMERIC_LEN
* 3];
1082 len
= sizeof(SQL_NUMERIC_STRUCT
);
1084 ns
= (SQL_NUMERIC_STRUCT
*) rgbValueBindRow
;
1086 ns
= (SQL_NUMERIC_STRUCT
*) rgbValue
+ bind_row
;
1087 for (wv
= neut_str
; *wv
&& isspace(*wv
); wv
++)
1094 } else if (*wv
== '+')
1100 for (nlen
= 0, dot_exist
= FALSE
;; wv
++)
1107 } else if (!isdigit(*wv
))
1117 memset(ns
->val
, 0, sizeof(ns
->val
));
1118 for (hval
= 0, bit
= 1L, sta
= 0, olen
= 0; sta
< nlen
;)
1120 for (dig
= 0, i
= sta
; i
< nlen
; i
++)
1122 tv
= dig
* 10 + calv
[i
] - '0';
1124 calv
[i
] = tv
/ 2 + '0';
1125 if (i
== sta
&& tv
< 2)
1131 if (bit
>= (1L << 8))
1133 ns
->val
[olen
++] = hval
;
1136 if (olen
>= SQL_MAX_NUMERIC_LEN
- 1)
1138 ns
->scale
= sta
- ns
->precision
;
1143 if (hval
&& olen
< SQL_MAX_NUMERIC_LEN
- 1)
1144 ns
->val
[olen
++] = hval
;
1146 #ifdef HAVE_LOCALE_H
1147 /* setlocale(LC_ALL, saved_locale); */
1148 #endif /* HAVE_LOCALE_H */
1155 *((SQLSMALLINT
*) rgbValueBindRow
) = atoi(neut_str
);
1157 *((SQLSMALLINT
*) rgbValue
+ bind_row
) = atoi(neut_str
);
1163 *((SQLUSMALLINT
*) rgbValueBindRow
) = atoi(neut_str
);
1165 *((SQLUSMALLINT
*) rgbValue
+ bind_row
) =
1173 *((SQLINTEGER
*) rgbValueBindRow
) = atol(neut_str
);
1175 *((SQLINTEGER
*) rgbValue
+ bind_row
) = atol(neut_str
);
1181 *((SQLUINTEGER
*) rgbValueBindRow
) = ATOI32U(neut_str
);
1183 *((SQLUINTEGER
*) rgbValue
+ bind_row
) =
1190 *((SQLBIGINT
*) rgbValueBindRow
) = ATOI64(neut_str
);
1192 *((SQLBIGINT
*) rgbValue
+ bind_row
) = ATOI64(neut_str
);
1198 *((SQLUBIGINT
*) rgbValueBindRow
) = ATOI64U(neut_str
);
1200 *((SQLUBIGINT
*) rgbValue
+ bind_row
) =
1205 if (PG_TYPE_UNKNOWN
== field_type
||
1206 PG_TYPE_TEXT
== field_type
||
1207 PG_TYPE_VARCHAR
== field_type
||
1208 PG_TYPE_BPCHAR
== field_type
||
1209 PG_TYPE_TEXTARRAY
== field_type
||
1210 PG_TYPE_VARCHARARRAY
== field_type
||
1211 PG_TYPE_BPCHARARRAY
== field_type
)
1213 ssize_t len
= SQL_NULL_DATA
;
1216 len
= strlen(neut_str
);
1218 *pcbValueBindRow
= len
;
1219 if (len
> 0 && cbValueMax
> 0)
1221 memcpy(rgbValueBindRow
, neut_str
,
1222 len
< cbValueMax
? len
: cbValueMax
);
1223 if (cbValueMax
>= len
+ 1)
1224 rgbValueBindRow
[len
] = '\0';
1226 if (cbValueMax
>= len
)
1229 return COPY_RESULT_TRUNCATED
;
1231 /* The following is for SQL_C_VARBOOKMARK */
1232 else if (PG_TYPE_INT4
== field_type
)
1234 UInt4 ival
= ATOI32U(neut_str
);
1236 inolog("SQL_C_VARBOOKMARK value=%d\n", ival
);
1238 *pcbValueBindRow
= sizeof(ival
);
1239 if (cbValueMax
>= sizeof(ival
))
1241 memcpy(rgbValueBindRow
, &ival
, sizeof(ival
));
1244 return COPY_RESULT_TRUNCATED
;
1245 } else if (PG_TYPE_BYTEA
!= field_type
)
1247 mylog("couldn't convert the type %d to SQL_C_BINARY\n",
1249 qlog("couldn't convert the type %d to SQL_C_BINARY\n",
1251 return COPY_UNSUPPORTED_TYPE
;
1253 /* truncate if necessary */
1254 /* convert octal escapes to bytes */
1256 if (stmt
->current_col
< 0)
1258 pgdc
= &(gdata
->fdata
);
1259 pgdc
->data_left
= -1;
1261 pgdc
= &gdata
->gdata
[stmt
->current_col
];
1263 pgdc
->ttlbuflen
= 0;
1264 if (pgdc
->data_left
< 0)
1266 if (cbValueMax
<= 0)
1268 len
= convert_from_pgbinary((const UCHAR
*)neut_str
, NULL
, 0);
1269 result
= COPY_RESULT_TRUNCATED
;
1273 strlen(neut_str
), len
>= (int) pgdc
->ttlbuflen
)
1275 pgdc
->ttlbuf
= (char *)realloc(pgdc
->ttlbuf
, len
+ 1);
1276 pgdc
->ttlbuflen
= len
+ 1;
1279 convert_from_pgbinary((const UCHAR
*)neut_str
,
1280 (UCHAR
*)pgdc
->ttlbuf
,
1282 pgdc
->ttlbufused
= len
;
1284 len
= pgdc
->ttlbufused
;
1287 if (stmt
->current_col
>= 0)
1290 * Second (or more) call to SQLGetData so move the
1293 if (pgdc
->data_left
> 0)
1295 ptr
+= len
- pgdc
->data_left
;
1296 len
= pgdc
->data_left
;
1299 /* First call to SQLGetData so initialize data_left */
1301 pgdc
->data_left
= len
;
1307 copy_len
= (len
> cbValueMax
) ? cbValueMax
: len
;
1310 memcpy(rgbValueBindRow
, ptr
, copy_len
);
1312 /* Adjust data_left for next time */
1313 if (stmt
->current_col
>= 0)
1314 pgdc
->data_left
-= copy_len
;
1318 * Finally, check for truncation so that proper status can
1321 if (len
> cbValueMax
)
1322 result
= COPY_RESULT_TRUNCATED
;
1323 else if (pgdc
->ttlbuf
)
1326 pgdc
->ttlbuf
= NULL
;
1328 mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len
,
1333 qlog("conversion to the type %d isn't supported\n", fCType
);
1334 return COPY_UNSUPPORTED_TYPE
;
1338 /* store the length of what was copied, if there's a place for it */
1340 *pcbValueBindRow
= len
;
1342 if (result
== COPY_OK
&& stmt
->current_col
>= 0)
1343 gdata
->gdata
[stmt
->current_col
].data_left
= 0;
1349 /*--------------------------------------------------------------------
1350 * Functions/Macros to get rid of query size limit.
1352 * I always used the follwoing macros to convert from
1353 * old_statement to new_statement. Please improve it
1354 * if you have a better way. Hiroshi 2001/05/22
1355 *--------------------------------------------------------------------
1358 #define FLGP_PREPARE_DUMMY_CURSOR 1L
1359 #define FLGP_CURSOR_CHECK_OK (1L << 1)
1360 #define FLGP_SELECT_INTO (1L << 2)
1361 #define FLGP_SELECT_FOR_UPDATE (1L << 3)
1362 #define FLGP_BUILDING_PREPARE_STATEMENT (1L << 4)
1363 #define FLGP_MULTIPLE_STATEMENT (1L << 5)
1364 typedef struct _QueryParse
{
1365 const char *statement
;
1368 Int4 from_pos
; /* PG comm length restriction */
1369 Int4 where_pos
; /* PG comm length restriction */
1371 char in_literal
, in_identifier
, in_escape
, in_dollar_quote
;
1372 const char *dollar_tag
;
1374 char token_save
[64];
1376 BOOL prev_token_end
;
1384 QP_initialize(QueryParse
* q
, const StatementClass
* stmt
)
1387 stmt
->execute_statement
? stmt
->execute_statement
: stmt
->
1389 q
->statement_type
= stmt
->statement_type
;
1393 q
->stmt_len
= (q
->statement
) ? strlen(q
->statement
) : -1;
1394 q
->in_literal
= q
->in_identifier
= q
->in_escape
=
1395 q
->in_dollar_quote
= FALSE
;
1396 q
->dollar_tag
= NULL
;
1398 q
->token_save
[0] = '\0';
1400 q
->prev_token_end
= TRUE
;
1401 q
->proc_no_param
= TRUE
;
1404 make_encoded_str(&q
->encstr
, SC_get_conn(stmt
), q
->statement
);
1409 #define FLGB_PRE_EXECUTING 1L
1410 #define FLGB_BUILDING_PREPARE_STATEMENT (1L << 1)
1411 #define FLGB_BUILDING_BIND_REQUEST (1L << 2)
1412 #define FLGB_EXECUTE_PREPARED (1L << 3)
1414 #define FLGB_INACCURATE_RESULT (1L << 4)
1415 #define FLGB_CREATE_KEYSET (1L << 5)
1416 #define FLGB_KEYSET_DRIVEN (1L << 6)
1417 #define FLGB_CONVERT_LF (1L << 7)
1418 #define FLGB_DISCARD_OUTPUT (1L << 8)
1419 #define FLGB_BINARY_AS_POSSIBLE (1L << 9)
1420 #define FLGB_LITERAL_EXTENSION (1L << 10)
1421 typedef struct _QueryBuild
{
1422 char *query_statement
;
1423 size_t str_size_limit
;
1430 Int2 num_output_params
;
1431 Int2 num_discard_params
;
1435 size_t load_stmt_len
;
1439 const char *errormsg
;
1441 ConnectionClass
*conn
; /* mainly needed for LO handling */
1442 StatementClass
*stmt
; /* needed to set error info in ENLARGE_.. */
1445 #define INIT_MIN_ALLOC 4096
1447 QB_initialize(QueryBuild
* qb
, size_t size
, StatementClass
* stmt
,
1448 ConnectionClass
* conn
)
1453 qb
->load_stmt_len
= 0;
1457 qb
->proc_return
= 0;
1458 qb
->num_io_params
= 0;
1459 qb
->num_output_params
= 0;
1460 qb
->num_discard_params
= 0;
1467 qb
->apdopts
= SC_get_APDF(stmt
);
1468 qb
->ipdopts
= SC_get_IPDF(stmt
);
1469 qb
->conn
= SC_get_conn(stmt
);
1470 if (stmt
->pre_executing
)
1471 qb
->flags
|= FLGB_PRE_EXECUTING
;
1472 if (stmt
->discard_output_params
)
1473 qb
->flags
|= FLGB_DISCARD_OUTPUT
;
1475 CountParameters(stmt
, NULL
, &dummy
, &qb
->num_output_params
);
1476 qb
->proc_return
= stmt
->proc_return
;
1477 if (0 != (qb
->flags
& FLGB_DISCARD_OUTPUT
))
1478 qb
->num_discard_params
= qb
->num_output_params
;
1479 if (qb
->num_discard_params
< qb
->proc_return
)
1480 qb
->num_discard_params
= qb
->proc_return
;
1486 if (qb
->conn
->connInfo
.lf_conversion
)
1487 qb
->flags
|= FLGB_CONVERT_LF
;
1488 qb
->ccsc
= qb
->conn
->ccsc
;
1489 if (CC_get_escape(qb
->conn
) && PG_VERSION_GE(qb
->conn
, 8.1))
1490 qb
->flags
|= FLGB_LITERAL_EXTENSION
;
1493 qb
->str_size_limit
= stmt
->stmt_size_limit
;
1495 qb
->str_size_limit
= -1;
1496 if (qb
->str_size_limit
> 0)
1498 if (size
> qb
->str_size_limit
)
1500 newsize
= qb
->str_size_limit
;
1504 newsize
= INIT_MIN_ALLOC
;
1505 while (newsize
<= size
)
1508 if ((qb
->query_statement
= (char *)malloc(newsize
)) == NULL
)
1513 qb
->query_statement
[0] = '\0';
1514 qb
->str_alsize
= newsize
;
1517 stmt
->exec_current_row
< 0 ? 0 : stmt
->exec_current_row
;
1518 qb
->param_number
= -1;
1519 qb
->dollar_number
= 0;
1520 qb
->errornumber
= 0;
1521 qb
->errormsg
= NULL
;
1527 QB_initialize_copy(QueryBuild
* qb_to
, const QueryBuild
* qb_from
,
1530 memcpy(qb_to
, qb_from
, sizeof(QueryBuild
));
1532 if (qb_to
->str_size_limit
> 0)
1534 if (size
> qb_to
->str_size_limit
)
1537 if ((qb_to
->query_statement
= (char *)malloc(size
)) == NULL
)
1539 qb_to
->str_alsize
= 0;
1542 qb_to
->query_statement
[0] = '\0';
1543 qb_to
->str_alsize
= size
;
1550 QB_replace_SC_error(StatementClass
* stmt
, const QueryBuild
* qb
,
1555 if (0 == qb
->errornumber
)
1557 if ((number
= SC_get_errornumber(stmt
)) > 0)
1559 if (number
< 0 && qb
->errornumber
< 0)
1561 SC_set_error(stmt
, qb
->errornumber
, qb
->errormsg
, func
);
1564 static void QB_Destructor(QueryBuild
* qb
)
1566 if (qb
->query_statement
)
1568 free(qb
->query_statement
);
1569 qb
->query_statement
= NULL
;
1575 * New macros (Aceto)
1576 *--------------------
1579 #define F_OldChar(qp) \
1580 qp->statement[qp->opos]
1582 #define F_OldPtr(qp) \
1583 (qp->statement + qp->opos)
1585 #define F_OldNext(qp) \
1588 #define F_OldPrior(qp) \
1591 #define F_OldPos(qp) \
1594 #define F_ExtractOldTo(qp, buf, ch, maxsize) \
1597 while (qp->statement[qp->opos] != '\0' && qp->statement[qp->opos] != ch) \
1601 buf[c++] = qp->statement[qp->opos++]; \
1603 if (qp->statement[qp->opos] == '\0') \
1608 #define F_NewChar(qb) \
1609 qb->query_statement[qb->npos]
1611 #define F_NewPtr(qb) \
1612 (qb->query_statement + qb->npos)
1614 #define F_NewNext(qb) \
1617 #define F_NewPos(qb) \
1622 convert_to_pgbinary(const UCHAR
* in
, char *out
, size_t len
,
1625 static ssize_t
enlarge_query_statement(QueryBuild
* qb
, size_t newsize
)
1627 size_t newalsize
= INIT_MIN_ALLOC
;
1628 CSTR func
= "enlarge_statement";
1630 if (qb
->str_size_limit
> 0 && qb
->str_size_limit
< (int) newsize
)
1632 free(qb
->query_statement
);
1633 qb
->query_statement
= NULL
;
1638 SC_set_error(qb
->stmt
, STMT_EXEC_ERROR
,
1639 "Query buffer overflow in copy_statement_with_parameters",
1644 "Query buffer overflow in copy_statement_with_parameters";
1645 qb
->errornumber
= STMT_EXEC_ERROR
;
1649 while (newalsize
<= newsize
)
1652 (qb
->query_statement
= (char *)realloc(qb
->query_statement
, newalsize
)))
1657 SC_set_error(qb
->stmt
, STMT_EXEC_ERROR
,
1658 "Query buffer allocate error in copy_statement_with_parameters",
1663 "Query buffer allocate error in copy_statement_with_parameters";
1664 qb
->errornumber
= STMT_EXEC_ERROR
;
1668 qb
->str_alsize
= newalsize
;
1673 * Enlarge stmt_with_params if necessary.
1676 #define ENLARGE_NEWSTATEMENT(qb, newpos) \
1677 if (newpos >= qb->str_alsize) \
1679 if (enlarge_query_statement(qb, newpos) <= 0) \
1684 * Terminate the stmt_with_params string with NULL.
1687 #define CVT_TERMINATE(qb) \
1689 qb->query_statement[qb->npos] = '\0'; \
1696 #define CVT_APPEND_DATA(qb, s, len) \
1698 size_t newpos = qb->npos + len; \
1699 ENLARGE_NEWSTATEMENT(qb, newpos) \
1700 memcpy(&qb->query_statement[qb->npos], s, len); \
1701 qb->npos = newpos; \
1702 qb->query_statement[newpos] = '\0'; \
1709 #define CVT_APPEND_STR(qb, s) \
1711 size_t len = strlen(s); \
1712 CVT_APPEND_DATA(qb, s, len); \
1719 #define CVT_APPEND_CHAR(qb, c) \
1721 ENLARGE_NEWSTATEMENT(qb, qb->npos + 1); \
1722 qb->query_statement[qb->npos++] = c; \
1726 * Append a binary data.
1727 * Newly reqeuired size may be overestimated currently.
1730 #define CVT_APPEND_BINARY(qb, buf, used) \
1732 size_t newlimit = qb->npos + 5 * used; \
1733 ENLARGE_NEWSTATEMENT(qb, newlimit); \
1734 qb->npos += convert_to_pgbinary((const UCHAR *)buf, &qb->query_statement[qb->npos], used, qb); \
1741 #define CVT_SPECIAL_CHARS(qb, buf, used) \
1743 size_t cnvlen = convert_special_chars(buf, NULL, used, qb->flags, qb->ccsc, CC_get_escape(qb->conn)); \
1744 size_t newlimit = qb->npos + cnvlen; \
1746 ENLARGE_NEWSTATEMENT(qb, newlimit); \
1747 convert_special_chars(buf, &qb->query_statement[qb->npos], used, qb->flags, qb->ccsc, CC_get_escape(qb->conn)); \
1748 qb->npos += cnvlen; \
1752 #define CVT_TEXT_FIELD(qb, buf, used) \
1754 char escape_ch = CC_get_escape(qb->conn); \
1755 int flags = ((0 != qb->flags & FLGB_CONVERT_LF) ? CONVERT_CRLF_TO_LF : 0) | ((0 != qb->flags & FLGB_BUILDING_BIND_REQUEST) ? 0 : DOUBLE_LITERAL_QUOTE | (escape_ch ? DOUBLE_LITERAL_IN_ESCAPE : 0)); \
1756 int cnvlen = (flags & (DOUBLE_LITERAL_QUOTE | DOUBLE_LITERAL_IN_ESCAPE)) != 0 ? used * 2 : used; \
1757 if (used > 0 && qb->npos + cnvlen >= qb->str_alsize) \
1759 cnvlen = convert_text_field(buf, NULL, used, qb->ccsc, escape_ch, &flags); \
1760 size_t newlimit = qb->npos + cnvlen; \
1762 ENLARGE_NEWSTATEMENT(qb, newlimit); \
1764 cnvlen = convert_text_field(buf, &qb->query_statement[qb->npos], used, qb->ccsc, escape_ch, &flags); \
1765 qb->npos += cnvlen; \
1767 #endif /* NOT_USED */
1770 * Check if the statement is
1771 * SELECT ... INTO table FROM .....
1772 * This isn't really a strict check but ...
1775 static BOOL
into_table_from(const char *stmt
)
1777 if (strnicmp(stmt
, "into", 4))
1780 if (!isspace((UCHAR
) * stmt
))
1782 while (isspace((UCHAR
) * (++stmt
)));
1789 case IDENTIFIER_QUOTE
: /* double quoted table name ? */
1793 while (*(++stmt
) != IDENTIFIER_QUOTE
&& *stmt
);
1794 while (*stmt
&& *(++stmt
) == IDENTIFIER_QUOTE
);
1795 while (*stmt
&& !isspace((UCHAR
) * stmt
)
1796 && *stmt
!= IDENTIFIER_QUOTE
)
1799 while (*stmt
== IDENTIFIER_QUOTE
);
1802 while (!isspace((UCHAR
) * (++stmt
)));
1807 while (isspace((UCHAR
) * (++stmt
)));
1808 if (strnicmp(stmt
, "from", 4))
1810 return isspace((UCHAR
) stmt
[4]);
1814 * Check if the statement is
1815 * SELECT ... FOR UPDATE .....
1816 * This isn't really a strict check but ...
1819 static BOOL
table_for_update(const char *stmt
, int *endpos
)
1821 const char *wstmt
= stmt
;
1823 while (isspace((UCHAR
) * (++wstmt
)));
1826 if (strnicmp(wstmt
, "update", 6))
1829 *endpos
= wstmt
- stmt
;
1830 return !wstmt
[0] || isspace((UCHAR
) wstmt
[0]);
1834 * Check if the statement has OUTER JOIN
1835 * This isn't really a strict check but ...
1839 check_join(StatementClass
* stmt
, const char *curptr
, size_t curpos
)
1842 ssize_t stapos
, endpos
, tokenwd
;
1843 const int backstep
= 4;
1846 for (endpos
= curpos
, wstmt
= curptr
;
1847 endpos
>= 0 && isspace((UCHAR
) * wstmt
); endpos
--, wstmt
--)
1851 for (endpos
-= backstep
, wstmt
-= backstep
;
1852 endpos
>= 0 && isspace((UCHAR
) * wstmt
); endpos
--, wstmt
--)
1856 for (stapos
= endpos
; stapos
>= 0 && !isspace((UCHAR
) * wstmt
);
1862 switch (tokenwd
= endpos
- stapos
)
1865 if (strnicmp(wstmt
, "FULL", tokenwd
) == 0 ||
1866 strnicmp(wstmt
, "LEFT", tokenwd
) == 0)
1870 if (strnicmp(wstmt
, "OUTER", tokenwd
) == 0 ||
1871 strnicmp(wstmt
, "RIGHT", tokenwd
) == 0)
1873 if (strnicmp(wstmt
, "INNER", tokenwd
) == 0 ||
1874 strnicmp(wstmt
, "CROSS", tokenwd
) == 0)
1886 SC_set_outer_join(stmt
);
1888 SC_set_inner_join(stmt
);
1894 * Check if the statement is
1895 * INSERT INTO ... () VALUES ()
1896 * This isn't really a strict check but ...
1899 static BOOL
insert_without_target(const char *stmt
, int *endpos
)
1901 const char *wstmt
= stmt
;
1903 while (isspace((UCHAR
) * (++wstmt
)));
1906 if (strnicmp(wstmt
, "VALUES", 6))
1909 if (!wstmt
[0] || !isspace((UCHAR
) wstmt
[0]))
1911 while (isspace((UCHAR
) * (++wstmt
)));
1912 if (*wstmt
!= '(' || *(++wstmt
) != ')')
1915 *endpos
= wstmt
- stmt
;
1916 return !wstmt
[0] || isspace((UCHAR
) wstmt
[0]) || ';' == wstmt
[0];
1919 #define my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
1921 static void remove_declare_cursor(QueryBuild
* qb
, QueryParse
* qp
)
1923 memmove(qb
->query_statement
, qb
->query_statement
+ qp
->declare_pos
,
1924 qb
->npos
- qp
->declare_pos
);
1925 qb
->npos
-= qp
->declare_pos
;
1926 qp
->declare_pos
= 0;
1929 Int4
findTag(const char *tag
, char dollar_quote
, int ccsc
)
1936 encoded_str_constr(&encstr
, ccsc
, tag
+ 1);
1937 for (sptr
= tag
+ 1; *sptr
; sptr
++)
1939 tchar
= encoded_nextchar(&encstr
);
1940 if (ENCODE_STATUS(encstr
) != 0)
1942 if (dollar_quote
== tchar
)
1944 taglen
= sptr
- tag
+ 1;
1953 static int inner_process_tokens(QueryParse
* qp
, QueryBuild
* qb
)
1955 CSTR func
= "inner_process_tokens";
1956 BOOL lf_conv
= ((qb
->flags
& FLGB_CONVERT_LF
) != 0);
1957 const char *bestitem
= NULL
;
1961 StatementClass
*stmt
= qb
->stmt
;
1962 char literal_quote
= LITERAL_QUOTE
, dollar_quote
=
1963 DOLLAR_QUOTE
, escape_in_literal
= '\0';
1965 if (stmt
&& stmt
->ntab
> 0)
1966 bestitem
= GET_NAME(stmt
->ti
[0]->bestitem
);
1967 if (qp
->from_pos
== (Int4
) qp
->opos
)
1969 CVT_APPEND_STR(qb
, ", \"ctid");
1972 CVT_APPEND_STR(qb
, "\", \"");
1973 CVT_APPEND_STR(qb
, bestitem
);
1975 CVT_APPEND_STR(qb
, "\" ");
1976 } else if (qp
->where_pos
== (Int4
) qp
->opos
)
1978 qb
->load_stmt_len
= qb
->npos
;
1979 if (0 != (qb
->flags
& FLGB_KEYSET_DRIVEN
))
1981 CVT_APPEND_STR(qb
, "where ctid = '(0,0)';select \"ctid");
1984 CVT_APPEND_STR(qb
, "\", \"");
1985 CVT_APPEND_STR(qb
, bestitem
);
1987 CVT_APPEND_STR(qb
, "\" from ");
1988 CVT_APPEND_DATA(qb
, qp
->statement
+ qp
->from_pos
+ 5,
1989 qp
->where_pos
- qp
->from_pos
- 5);
1992 oldchar
= encoded_byte_check(&qp
->encstr
, qp
->opos
);
1993 if (ENCODE_STATUS(qp
->encstr
) != 0)
1995 CVT_APPEND_CHAR(qb
, oldchar
);
2000 * From here we are guaranteed to handle a 1-byte character.
2002 if (qp
->in_escape
) /* escape check */
2004 qp
->in_escape
= FALSE
;
2005 CVT_APPEND_CHAR(qb
, oldchar
);
2007 } else if (qp
->in_dollar_quote
) /* dollar quote check */
2009 if (oldchar
== dollar_quote
)
2011 if (strncmp(F_OldPtr(qp
), qp
->dollar_tag
, qp
->taglen
) == 0)
2013 CVT_APPEND_DATA(qb
, F_OldPtr(qp
), qp
->taglen
);
2014 qp
->opos
+= (qp
->taglen
- 1);
2015 qp
->in_dollar_quote
= FALSE
;
2016 qp
->in_literal
= FALSE
;
2017 qp
->dollar_tag
= NULL
;
2022 CVT_APPEND_CHAR(qb
, oldchar
);
2024 } else if (qp
->in_literal
) /* quote check */
2026 if (oldchar
== escape_in_literal
)
2027 qp
->in_escape
= TRUE
;
2028 else if (oldchar
== literal_quote
)
2029 qp
->in_literal
= FALSE
;
2030 CVT_APPEND_CHAR(qb
, oldchar
);
2032 } else if (qp
->in_identifier
) /* double quote check */
2034 if (oldchar
== IDENTIFIER_QUOTE
)
2035 qp
->in_identifier
= FALSE
;
2036 CVT_APPEND_CHAR(qb
, oldchar
);
2041 * From here we are guranteed to be in neither a literal_escape,
2042 * a literal_quote nor an idetifier_quote.
2044 /* Squeeze carriage-return/linefeed pairs to linefeed only */
2046 PG_CARRIAGE_RETURN
== oldchar
&&
2047 qp
->opos
+ 1 < qp
->stmt_len
&&
2048 PG_LINEFEED
== qp
->statement
[qp
->opos
+ 1])
2052 * Handle literals (date, time, timestamp) and ODBC scalar
2055 else if (oldchar
== '{')
2057 qb
->errornumber
= STMT_EXEC_ERROR
;
2058 qb
->errormsg
= "ODBC functions not yet supported";
2061 /* End of an escape sequence */
2062 else if (oldchar
== '}')
2064 if (qp
->statement_type
== STMT_TYPE_PROCCALL
)
2066 if (qp
->proc_no_param
)
2067 CVT_APPEND_STR(qb
, "()");
2068 } else if (!isspace(F_OldPtr(qp
)[1]))
2069 CVT_APPEND_CHAR(qb
, ' ');
2071 } else if (oldchar
== '@' &&
2072 strnicmp(F_OldPtr(qp
), "@@identity", 10) == 0)
2074 ConnectionClass
*conn
= SC_get_conn(stmt
);
2075 BOOL converted
= FALSE
;
2078 if (PG_VERSION_GE(conn
, 8.1))
2080 CVT_APPEND_STR(qb
, "lastval()");
2082 } else if (NAME_IS_VALID(conn
->tableIns
))
2084 TABLE_INFO ti
, *pti
= &ti
;
2086 memset(&ti
, 0, sizeof(ti
));
2087 NAME_TO_NAME(ti
.schema_name
, conn
->schemaIns
);
2088 NAME_TO_NAME(ti
.table_name
, conn
->tableIns
);
2089 getCOLIfromTI(func
, conn
, NULL
, 0, &pti
);
2091 NULL_THE_NAME(ti
.schema_name
);
2092 NULL_THE_NAME(ti
.table_name
);
2095 int i
, num_fields
= QR_NumResultCols(coli
->result
);
2097 for (i
= 0; i
< num_fields
; i
++)
2101 QR_get_value_backend_text(coli
->result
, i
,
2102 COLUMNS_AUTO_INCREMENT
))
2105 CVT_APPEND_STR(qb
, "curr");
2108 QR_get_value_backend_text(coli
->
2120 CVT_APPEND_STR(qb
, "NULL");
2126 * Can you have parameter markers inside of quotes? I dont think
2127 * so. All the queries I've seen expect the driver to put quotes
2130 else if (oldchar
!= '?')
2132 if (oldchar
== dollar_quote
)
2135 findTag(F_OldPtr(qp
), dollar_quote
, qp
->encstr
.ccsc
);
2138 qp
->in_literal
= TRUE
;
2139 qp
->in_dollar_quote
= TRUE
;
2140 qp
->dollar_tag
= F_OldPtr(qp
);
2141 CVT_APPEND_DATA(qb
, F_OldPtr(qp
), qp
->taglen
);
2142 qp
->opos
+= (qp
->taglen
- 1);
2145 } else if (oldchar
== literal_quote
)
2147 if (!qp
->in_identifier
)
2149 qp
->in_literal
= TRUE
;
2150 escape_in_literal
= CC_get_escape(qb
->conn
);
2151 if (!escape_in_literal
)
2153 if (LITERAL_EXT
== F_OldPtr(qp
)[-1])
2154 escape_in_literal
= ESCAPE_IN_LITERAL
;
2157 } else if (oldchar
== IDENTIFIER_QUOTE
)
2159 if (!qp
->in_literal
)
2160 qp
->in_identifier
= TRUE
;
2161 } else if (oldchar
== ';')
2164 * can't parse multiple statement using protocol V3.
2165 * reset the dollar number here in case it is divided
2168 qb
->dollar_number
= 0;
2169 if (0 != (qp
->flags
& FLGP_CURSOR_CHECK_OK
))
2171 const char *vp
= &(qp
->statement
[qp
->opos
+ 1]);
2173 while (*vp
&& isspace(*vp
))
2175 if (*vp
) /* multiple statement */
2177 qp
->flags
|= FLGP_MULTIPLE_STATEMENT
;
2178 qp
->flags
&= ~FLGP_CURSOR_CHECK_OK
;
2179 qb
->flags
&= ~FLGB_KEYSET_DRIVEN
;
2180 remove_declare_cursor(qb
, qp
);
2185 if (isspace((UCHAR
) oldchar
))
2187 if (!qp
->prev_token_end
)
2189 qp
->prev_token_end
= TRUE
;
2190 qp
->token_save
[qp
->token_len
] = '\0';
2191 if (qp
->token_len
== 4)
2193 if (0 != (qp
->flags
& FLGP_CURSOR_CHECK_OK
) &&
2194 into_table_from(&qp
->
2195 statement
[qp
->opos
-
2198 qp
->flags
|= FLGP_SELECT_INTO
;
2199 qp
->flags
&= ~FLGP_CURSOR_CHECK_OK
;
2200 qb
->flags
&= ~FLGB_KEYSET_DRIVEN
;
2201 qp
->statement_type
= STMT_TYPE_CREATE
;
2202 remove_declare_cursor(qb
, qp
);
2203 } else if (stricmp(qp
->token_save
, "join") == 0)
2206 check_join(stmt
, F_OldPtr(qp
),
2209 } else if (qp
->token_len
== 3)
2213 if (0 != (qp
->flags
& FLGP_CURSOR_CHECK_OK
) &&
2214 strnicmp(qp
->token_save
, "for", 3) == 0 &&
2215 table_for_update(F_OldPtr(qp
), &endpos
))
2217 qp
->flags
|= FLGP_SELECT_FOR_UPDATE
;
2218 qp
->flags
&= ~FLGP_CURSOR_CHECK_OK
;
2219 if (qp
->flags
& FLGP_PREPARE_DUMMY_CURSOR
)
2225 remove_declare_cursor(qb
, qp
);
2228 } else if (qp
->token_len
== 2)
2232 if (STMT_TYPE_INSERT
== qp
->statement_type
&&
2233 strnicmp(qp
->token_save
, "()", 2) == 0 &&
2234 insert_without_target(F_OldPtr(qp
),
2238 CVT_APPEND_STR(qb
, "DEFAULT VALUES");
2244 } else if (qp
->prev_token_end
)
2246 qp
->prev_token_end
= FALSE
;
2247 qp
->token_save
[0] = oldchar
;
2249 } else if (qp
->token_len
+ 1 < sizeof(qp
->token_save
))
2250 qp
->token_save
[qp
->token_len
++] = oldchar
;
2252 CVT_APPEND_CHAR(qb
, oldchar
);
2257 * Its a '?' parameter alright
2259 if (0 == qb
->errornumber
)
2261 qb
->errornumber
= STMT_EXEC_ERROR
;
2262 qb
->errormsg
= "SQL bound parameters not yet supported";
2264 mylog("%s convert_escape error\n", func
);
2269 ResolveNumericParam(const SQL_NUMERIC_STRUCT
* ns
, char *chrform
)
2271 static const int prec
[] =
2272 { 1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37,
2275 Int4 i
, j
, k
, ival
, vlen
, len
, newlen
;
2277 const UCHAR
*val
= (const UCHAR
*) ns
->val
;
2280 inolog("C_NUMERIC [prec=%d scale=%d]", ns
->precision
, ns
->scale
);
2281 if (0 == ns
->precision
)
2283 strcpy(chrform
, "0");
2285 } else if (ns
->precision
< prec
[sizeof(Int4
)])
2287 for (i
= 0, ival
= 0;
2288 i
< sizeof(Int4
) && prec
[i
] <= ns
->precision
; i
++)
2290 inolog("(%d)", val
[i
]);
2291 ival
+= (val
[i
] << (8 * i
)); /* ns->val is little endian */
2293 inolog(" ival=%d,%d", ival
,
2294 (val
[3] << 24) | (val
[2] << 16) | (val
[1] << 8) |
2300 sprintf(chrform
, "%d", ival
);
2301 } else if (ns
->scale
> 0)
2303 Int4 i
, div
, o1val
, o2val
;
2305 for (i
= 0, div
= 1; i
< ns
->scale
; i
++)
2311 sprintf(chrform
, "%d.%0.*d", o1val
, ns
->scale
, o2val
);
2313 inolog(" convval=%s\n", chrform
);
2317 for (i
= 0; i
< SQL_MAX_NUMERIC_LEN
&& prec
[i
] <= ns
->precision
;
2322 memset(calv
, 0, sizeof(calv
));
2323 inolog(" len1=%d", vlen
);
2324 for (i
= vlen
- 1; i
>= 0; i
--)
2326 for (j
= len
- 1; j
>= 0; j
--)
2330 ival
= (((Int4
) calv
[j
]) << 8);
2331 calv
[j
] = (ival
% 10);
2333 calv
[j
+ 1] += (ival
% 10);
2335 calv
[j
+ 2] += (ival
% 10);
2337 calv
[j
+ 3] += ival
;
2340 next_figure
= FALSE
;
2352 if (k
>= j
+ 3 && !next_figure
)
2359 calv
[0] += (ival
% 10);
2361 calv
[1] += (ival
% 10);
2366 next_figure
= FALSE
;
2378 if (j
>= 2 && !next_figure
)
2382 inolog(" len2=%d", len
);
2385 chrform
[newlen
++] = '-';
2386 if (i
= len
- 1, i
< ns
->scale
)
2388 for (; i
>= ns
->scale
; i
--)
2389 chrform
[newlen
++] = calv
[i
] + '0';
2392 chrform
[newlen
++] = '.';
2394 chrform
[newlen
++] = calv
[i
] + '0';
2397 chrform
[newlen
++] = '0';
2398 chrform
[newlen
] = '\0';
2399 inolog(" convval(2) len=%d %s\n", newlen
, chrform
);
2404 BOOL
convert_money(const char *s
, char *sout
, size_t soutmax
)
2406 size_t i
= 0, out
= 0;
2408 for (i
= 0; s
[i
]; i
++)
2410 if (s
[i
] == '$' || s
[i
] == ',' || s
[i
] == ')')
2411 ; /* skip these characters */
2414 if (out
+ 1 >= soutmax
)
2415 return FALSE
; /* sout is too short */
2428 * This function parses a character string for date/time info and fills in SIMPLE_TIME
2429 * It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value
2431 char parse_datetime(const char *buf
, SIMPLE_TIME
* st
)
2433 int y
, m
, d
, hh
, mm
, ss
;
2436 y
= m
= d
= hh
= mm
= ss
= 0;
2440 /* escape sequence ? */
2443 while (*(++buf
) && *buf
!= LITERAL_QUOTE
);
2448 if (buf
[4] == '-') /* year first */
2449 nf
= sscanf(buf
, "%4d-%2d-%2d %2d:%2d:%2d", &y
, &m
, &d
, &hh
,
2452 nf
= sscanf(buf
, "%2d-%2d-%4d %2d:%2d:%2d", &m
, &d
, &y
, &hh
,
2455 if (nf
== 5 || nf
== 6)
2467 if (buf
[4] == '-') /* year first */
2468 nf
= sscanf(buf
, "%4d-%2d-%2d", &y
, &m
, &d
);
2470 nf
= sscanf(buf
, "%2d-%2d-%4d", &m
, &d
, &y
);
2481 nf
= sscanf(buf
, "%2d:%2d:%2d", &hh
, &mm
, &ss
);
2482 if (nf
== 2 || nf
== 3)
2495 /* Change linefeed to carriage-return/linefeed */
2497 convert_linefeeds(const char *si
, char *dst
, size_t max
, BOOL convlf
,
2500 size_t i
= 0, out
= 0;
2505 for (i
= 0; si
[i
] && out
< max
- 1; i
++)
2507 if (convlf
&& si
[i
] == '\n')
2509 /* Only add the carriage-return if needed */
2510 if (i
> 0 && PG_CARRIAGE_RETURN
== si
[i
- 1])
2522 dst
[out
++] = PG_CARRIAGE_RETURN
;
2541 * Change carriage-return/linefeed to just linefeed
2542 * Plus, escape any special characters.
2545 convert_special_chars(const char *si
, char *dst
, SQLLEN used
,
2546 UInt4 flags
, int ccsc
, int escape_in_literal
)
2548 size_t i
= 0, out
= 0, max
;
2549 char *p
= NULL
, literal_quote
= LITERAL_QUOTE
, tchar
;
2551 BOOL convlf
= (0 != (flags
& FLGB_CONVERT_LF
)),
2552 double_special
= (0 == (flags
& FLGB_BUILDING_BIND_REQUEST
));
2554 if (used
== SQL_NTS
)
2563 encoded_str_constr(&encstr
, ccsc
, si
);
2565 for (i
= 0; i
< max
&& si
[i
]; i
++)
2567 tchar
= encoded_nextchar(&encstr
);
2568 if (ENCODE_STATUS(encstr
) != 0)
2575 if (convlf
&& /* CR/LF -> LF */
2576 PG_CARRIAGE_RETURN
== tchar
&& PG_LINEFEED
== si
[i
+ 1])
2578 else if (double_special
&& /* double special chars ? */
2579 (tchar
== literal_quote
|| tchar
== escape_in_literal
))
2597 #define CVT_CRLF_TO_LF 1L
2598 #define DOUBLE_LITERAL_QUOTE (1L << 1)
2599 #define DOUBLE_ESCAPE_IN_LITERAL (1L << 2)
2601 convert_text_field(const char *si
, char *dst
, int used
, int ccsc
,
2602 int escape_in_literal
, UInt4
* flags
)
2604 size_t i
= 0, out
= 0, max
;
2605 UInt4 iflags
= *flags
;
2606 char *p
= NULL
, literal_quote
= LITERAL_QUOTE
, tchar
;
2608 BOOL convlf
= (0 != (iflags
& CVT_CRLF_TO_LF
)),
2609 double_literal_quote
= (0 != (iflags
& DOUBLE_LITERAL_QUOTE
)),
2610 double_escape_in_literal
=
2611 (0 != (iflags
& DOUBLE_ESCAPE_IN_LITERAL
));
2613 if (SQL_NTS
== used
)
2620 strncpy_null(dst
, si
, max
+ 1);
2629 encoded_str_constr(&encstr
, ccsc
, si
);
2632 for (i
= 0; i
< max
&& si
[i
]; i
++)
2634 tchar
= encoded_nextchar(&encstr
);
2635 if (ENCODE_STATUS(encstr
) != 0)
2642 if (convlf
&& /* CR/LF -> LF */
2643 PG_CARRIAGE_RETURN
== tchar
&& PG_LINEFEED
== si
[i
+ 1])
2645 *flags
|= CVT_CRLF_TO_LF
;
2647 } else if (double_literal_quote
&& /* double literal quote ? */
2648 tchar
== literal_quote
)
2653 *flags
|= DOUBLE_LITERAL_QUOTE
;
2654 } else if (double_escape_in_literal
&& /* double escape ? */
2655 tchar
== escape_in_literal
)
2660 *flags
|= DOUBLE_ESCAPE_IN_LITERAL
;
2670 #endif /* NOT_USED */
2673 /* !!! Need to implement this function !!! */
2675 convert_pgbinary_to_char(const char *value
, char *rgbValue
,
2678 mylog("convert_pgbinary_to_char: value = '%s'\n", value
);
2680 strncpy_null(rgbValue
, value
, cbValueMax
);
2685 static int conv_from_octal(const UCHAR
* s
)
2690 for (i
= 1; i
<= 3; i
++)
2691 y
+= (s
[i
] - '0') << (3 * (3 - i
));
2697 /* convert octal escapes to bytes */
2699 convert_from_pgbinary(const UCHAR
* value
, UCHAR
* rgbValue
,
2702 size_t i
, ilen
= strlen((const char *)value
);
2706 for (i
= 0; i
< ilen
;)
2708 if (value
[i
] == BYTEA_ESCAPE_CHAR
)
2710 if (value
[i
+ 1] == BYTEA_ESCAPE_CHAR
)
2713 rgbValue
[o
] = value
[i
];
2718 rgbValue
[o
] = conv_from_octal(&value
[i
]);
2724 rgbValue
[o
] = value
[i
];
2728 mylog("convert_from_pgbinary: i=%d, rgbValue[%d] = %d, %c\n", i, o, rgbValue[o], rgbValue[o]); ***/
2733 rgbValue
[o
] = '\0'; /* extra protection */
2735 mylog("convert_from_pgbinary: in=%d, out = %d\n", ilen
, o
);
2741 static UInt2
conv_to_octal(UCHAR val
, char *octal
, char escape_ch
)
2743 int i
, pos
= 0, len
;
2746 octal
[pos
++] = escape_ch
;
2747 octal
[pos
] = BYTEA_ESCAPE_CHAR
;
2751 for (i
= len
- 1; i
> pos
; i
--)
2753 octal
[i
] = (val
& 7) + '0';
2761 static char *conv_to_octal2(UCHAR val
, char *octal
)
2765 octal
[0] = BYTEA_ESCAPE_CHAR
;
2768 for (i
= 3; i
> 0; i
--)
2770 octal
[i
] = (val
& 7) + '0';
2778 /* convert non-ascii bytes to octal escape sequences */
2780 convert_to_pgbinary(const UCHAR
* in
, char *out
, size_t len
,
2783 CSTR func
= "convert_to_pgbinary";
2786 char escape_in_literal
= CC_get_escape(qb
->conn
);
2787 BOOL esc_double
= (0 == (qb
->flags
& FLGB_BUILDING_BIND_REQUEST
)
2788 && 0 != escape_in_literal
);
2790 for (i
= 0; i
< len
; i
++)
2793 mylog("%s: in[%d] = %d, %c\n", func
, i
, inc
, inc
);
2794 if (inc
< 128 && (isalnum(inc
) || inc
== ' '))
2800 o
+= conv_to_octal(inc
, &out
[o
], escape_in_literal
);
2803 conv_to_octal2(inc
, &out
[o
]);
2809 mylog("%s: returning %d, out='%.*s'\n", func
, o
, o
, out
);
2815 static const char *hextbl
= "0123456789ABCDEF";
2816 static SQLLEN
pg_bin2hex(UCHAR
* src
, UCHAR
* dst
, SQLLEN length
)
2818 UCHAR chr
, *src_wk
, *dst_wk
;
2825 if (dst
+ length
> src
+ 1)
2827 } else if (dst
< src
+ length
)
2831 for (i
= 0, src_wk
= src
+ length
- 1, dst_wk
=
2832 dst
+ 2 * length
- 1; i
< length
; i
++, src_wk
--)
2835 *dst_wk
-- = hextbl
[chr
% 16];
2836 *dst_wk
-- = hextbl
[chr
>> 4];
2840 for (i
= 0, src_wk
= src
, dst_wk
= dst
; i
< length
;
2844 *dst_wk
++ = hextbl
[chr
>> 4];
2845 *dst_wk
++ = hextbl
[chr
% 16];
2848 dst
[2 * length
] = '\0';
2852 SQLLEN
pg_hex2bin(const UCHAR
* src
, UCHAR
* dst
, SQLLEN length
)
2855 const UCHAR
*src_wk
;
2861 for (i
= 0, src_wk
= src
, dst_wk
= dst
; i
< length
; i
++, src_wk
++)
2866 if (chr
>= 'a' && chr
<= 'f')
2867 val
= chr
- 'a' + 10;
2868 else if (chr
>= 'A' && chr
<= 'F')
2869 val
= chr
- 'A' + 10;
2873 *dst_wk
= (val
<< 4);