Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8cdabf0

Browse files
author
Thomas G. Lockhart
committed
Augment the function call map logic with code from Tom Lane.
Should be more robust to overflows. Pass through an unmapped function unchanged, rather than rejecting it. Add a few more functions, but comment out those which can go through as-is. Can be used with contrib/odbc/ package, though that isn't committed yet.
1 parent 51cfdae commit 8cdabf0

File tree

1 file changed

+129
-37
lines changed

1 file changed

+129
-37
lines changed

src/interfaces/odbc/convert.c

Lines changed: 129 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,76 @@ typedef signed char SCHAR;
5858

5959
extern 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

76133
char *mapFunction(char *func);
@@ -584,7 +641,7 @@ int
584641
copy_statement_with_parameters(StatementClass *stmt)
585642
{
586643
static char *func="copy_statement_with_parameters";
587-
unsigned int opos, npos;
644+
unsigned int opos, npos, oldstmtlen;
588645
char param_string[128], tmp[256], cbuf[TEXT_FIELD_SIZE+5];
589646
int param_number;
590647
Int2 param_ctype, param_sqltype;
@@ -629,14 +686,17 @@ int lobj_fd, retval;
629686

630687
param_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') {
636696
continue;
637697
}
638698

639-
// Handle literals (date, time, timestamp)
699+
// Handle literals (date, time, timestamp) and ODBC scalar functions
640700
else if (old_statement[opos] == '{') {
641701
char *esc;
642702
char *begin = &old_statement[opos + 1];
@@ -1056,37 +1116,69 @@ int i;
10561116
return 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+
*/
10601122
char *
10611123
convert_escape(char *value)
10621124
{
1063-
char key[32], val[256];
10641125
static 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
}
10891180
else {
1181+
/* Bogus key, leave untranslated */
10901182
return NULL;
10911183
}
10921184

0 commit comments

Comments
 (0)