@@ -58,19 +58,76 @@ typedef signed char SCHAR;
5858
5959extern GLOBAL_VALUES globals ;
6060
61- /*How to map ODBC scalar functions {fn func(args)} to Postgres */
62- /*This is just a simple substitution */
63- char * mapFuncs [][2 ]= {
64- {"CONCAT" ,"textcat" },
65- {"LCASE" ,"lower" },
66- {"LOCATE" ,"strpos" },
67- {"LENGTH" ,"textlen" },
68- {"LTRIM" ,"ltrim" },
69- {"RTRIM" ,"rtrim" },
70- {"SUBSTRING" ,"substr" },
71- {"UCASE" ,"upper" },
72- {"NOW" ,"now" },
73- {0 ,0 }
61+ /*How to map ODBC scalar functions {fn func(args)} to Postgres
62+ *This is just a simple substitution
63+ *List augmented from
64+ * http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm
65+ * - thomas 2000-04-03
66+ */
67+ char * mapFuncs [][2 ]= {
68+ //{ "ASCII", "ascii" },
69+ {"CHAR" ,"ichar" },
70+ {"CONCAT" ,"textcat" },
71+ //{ "DIFFERENCE", "difference" },
72+ //{ "INSERT", "insert" },
73+ {"LCASE" ,"lower" },
74+ {"LEFT" ,"ltrunc" },
75+ {"LOCATE" ,"strpos" },
76+ {"LENGTH" ,"char_length" },
77+ //{ "LTRIM", "ltrim" },
78+ {"RIGHT" ,"rtrunc" },
79+ //{ "REPEAT", "repeat" },
80+ //{ "REPLACE", "replace" },
81+ //{ "RTRIM", "rtrim" },
82+ //{ "SOUNDEX", "soundex" },
83+ {"SUBSTRING" ,"substr" },
84+ {"UCASE" ,"upper" },
85+
86+ //{ "ABS", "abs" },
87+ //{ "ACOS", "acos" },
88+ //{ "ASIN", "asin" },
89+ //{ "ATAN", "atan" },
90+ //{ "ATAN2", "atan2" },
91+ {"CEILING" ,"ceil" },
92+ //{ "COS", "cos" },
93+ //{ "COT", "cot" },
94+ //{ "DEGREES", "degrees" },
95+ //{ "EXP", "exp" },
96+ //{ "FLOOR", "floor" },
97+ {"LOG" ,"ln" },
98+ {"LOG10" ,"log" },
99+ //{ "MOD", "mod" },
100+ //{ "PI", "pi" },
101+ {"POWER" ,"pow" },
102+ //{ "RADIANS", "radians" },
103+ {"RAND" ,"random" },
104+ //{ "ROUND", "round" },
105+ //{ "SIGN", "sign" },
106+ //{ "SIN", "sin" },
107+ //{ "SQRT", "sqrt" },
108+ //{ "TAN", "tan" },
109+ //{ "TRUNCATE", "truncate" },
110+
111+ //{ "CURDATE", "curdate" },
112+ //{ "CURTIME", "curtime" },
113+ //{ "DAYNAME", "dayname" },
114+ //{ "DAYOFMONTH", "dayofmonth" },
115+ //{ "DAYOFWEEK", "dayofweek" },
116+ //{ "DAYOFYEAR", "dayofyear" },
117+ //{ "HOUR", "hour" },
118+ //{ "MINUTE", "minute" },
119+ //{ "MONTH", "month" },
120+ //{ "MONTHNAME", "monthname" },
121+ //{ "NOW", "now" },
122+ //{ "QUARTER", "quarter" },
123+ //{ "SECOND", "second" },
124+ //{ "WEEK", "week" },
125+ //{ "YEAR", "year" },
126+
127+ //{ "DATABASE", "database" },
128+ {"IFNULL" ,"coalesce" },
129+ {"USER" ,"odbc_user" },
130+ {0 ,0 }
74131};
75132
76133char * mapFunction (char * func );
584641copy_statement_with_parameters (StatementClass * stmt )
585642{
586643static char * func = "copy_statement_with_parameters" ;
587- unsignedint opos ,npos ;
644+ unsignedint opos ,npos , oldstmtlen ;
588645char param_string [128 ],tmp [256 ],cbuf [TEXT_FIELD_SIZE + 5 ];
589646int param_number ;
590647Int2 param_ctype ,param_sqltype ;
@@ -629,14 +686,17 @@ int lobj_fd, retval;
629686
630687param_number = -1 ;
631688
632- for (opos = 0 ;opos < strlen (old_statement );opos ++ ) {
689+ oldstmtlen = strlen (old_statement );
690+
691+ for (opos = 0 ;opos < oldstmtlen ;opos ++ ) {
633692
634693//Squeeze carriage-returns/linfeed pairs to linefeed only
635- if (old_statement [opos ]== '\r' && opos + 1 < strlen (old_statement )&& old_statement [opos + 1 ]== '\n' ) {
694+ if (old_statement [opos ]== '\r' && opos + 1 < oldstmtlen &&
695+ old_statement [opos + 1 ]== '\n' ) {
636696continue ;
637697}
638698
639- //Handle literals (date, time, timestamp)
699+ //Handle literals (date, time, timestamp) and ODBC scalar functions
640700else if (old_statement [opos ]== '{' ) {
641701char * esc ;
642702char * begin = & old_statement [opos + 1 ];
@@ -1056,37 +1116,69 @@ int i;
10561116return NULL ;
10571117}
10581118
1059- //This function returns a pointer to static memory!
1119+ /* convert_escape()
1120+ * This function returns a pointer to static memory!
1121+ */
10601122char *
10611123convert_escape (char * value )
10621124{
1063- char key [32 ],val [256 ];
10641125static char escape [1024 ];
1065- char func [32 ],the_rest [1024 ];
1066- char * mapFunc ;
1067-
1068- sscanf (value ,"%s %[^\r]" ,key ,val );
1126+ char key [33 ];
10691127
1070- mylog ("convert_escape: key='%s', val='%s'\n" ,key ,val );
1128+ /* Separate off the key, skipping leading and trailing whitespace */
1129+ while ((* value != '\0' )&& isspace (* value ))value ++ ;
1130+ sscanf (value ,"%32s" ,key );
1131+ while ((* value != '\0' )&& (!isspace (* value )))value ++ ;
1132+ while ((* value != '\0' )&& isspace (* value ))value ++ ;
10711133
1072- if ( !strcmp (key ,"d" )||
1073- !strcmp (key ,"t" )||
1074- !strcmp (key ,"ts" )) {
1134+ mylog ("convert_escape: key='%s', val='%s'\n" ,key ,value );
10751135
1076- strcpy (escape ,val );
1136+ if ( (strcmp (key ,"d" )== 0 )||
1137+ (strcmp (key ,"t" )== 0 )||
1138+ (strcmp (key ,"ts" )== 0 )) {
1139+ /* Literal; return the escape part as-is */
1140+ strncpy (escape ,value ,sizeof (escape )- 1 );
10771141}
1078- else if ( !strcmp (key ,"fn" )) {
1079- sscanf (val ,"%[^(]%[^\r]" ,func ,the_rest );
1080- mapFunc = mapFunction (func );
1081- if ( !mapFunc )
1082- return NULL ;
1083- else {
1084- strcpy (escape ,mapFunc );
1085- strcat (escape ,the_rest );
1142+ else if (strcmp (key ,"fn" )== 0 ) {
1143+ /* Function invocation
1144+ * Separate off the func name,
1145+ * skipping trailing whitespace.
1146+ */
1147+ char * funcEnd = value ;
1148+ char svchar ;
1149+ char * mapFunc ;
1150+
1151+ while ((* funcEnd != '\0' )&& (* funcEnd != '(' )&&
1152+ (!isspace (* funcEnd )))funcEnd ++ ;
1153+ svchar = * funcEnd ;
1154+ * funcEnd = '\0' ;
1155+ sscanf (value ,"%32s" ,key );
1156+ * funcEnd = svchar ;
1157+ while ((* funcEnd != '\0' )&& isspace (* funcEnd ))funcEnd ++ ;
1158+
1159+ /* We expect left parenthensis here,
1160+ * else return fn body as-is since it is
1161+ * one of those "function constants".
1162+ */
1163+ if (* funcEnd != '(' ) {
1164+ strncpy (escape ,value ,sizeof (escape )- 1 );
1165+ return escape ;
10861166}
1087-
1167+ mapFunc = mapFunction (key );
1168+ /* We could have mapFunction() return key if not in table...
1169+ * - thomas 2000-04-03
1170+ */
1171+ if (mapFunc == NULL ) {
1172+ /* If unrecognized function name, return fn body as-is */
1173+ strncpy (escape ,value ,sizeof (escape )- 1 );
1174+ return escape ;
1175+ }
1176+ /* copy mapped name and remaining input string */
1177+ strcpy (escape ,mapFunc );
1178+ strncat (escape ,funcEnd ,sizeof (escape )- strlen (mapFunc ));
10881179}
10891180else {
1181+ /* Bogus key, leave untranslated */
10901182return NULL ;
10911183}
10921184