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.
This commit is contained in:
Thomas G. Lockhart 2000-04-04 01:07:54 +00:00
parent 51cfdae50f
commit 8cdabf0741
1 changed files with 129 additions and 37 deletions

View File

@ -58,18 +58,75 @@ typedef signed char SCHAR;
extern GLOBAL_VALUES globals;
/* How to map ODBC scalar functions {fn func(args)} to Postgres */
/* This is just a simple substitution */
/* How to map ODBC scalar functions {fn func(args)} to Postgres
* This is just a simple substitution
* List augmented from
* http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm
* - thomas 2000-04-03
*/
char *mapFuncs[][2] = {
// { "ASCII", "ascii" },
{ "CHAR", "ichar" },
{ "CONCAT", "textcat" },
// { "DIFFERENCE", "difference" },
// { "INSERT", "insert" },
{ "LCASE", "lower" },
{ "LEFT", "ltrunc" },
{ "LOCATE", "strpos" },
{ "LENGTH", "textlen" },
{ "LTRIM", "ltrim" },
{ "RTRIM", "rtrim" },
{ "LENGTH", "char_length"},
// { "LTRIM", "ltrim" },
{ "RIGHT", "rtrunc" },
// { "REPEAT", "repeat" },
// { "REPLACE", "replace" },
// { "RTRIM", "rtrim" },
// { "SOUNDEX", "soundex" },
{ "SUBSTRING", "substr" },
{ "UCASE", "upper" },
{ "NOW", "now" },
// { "ABS", "abs" },
// { "ACOS", "acos" },
// { "ASIN", "asin" },
// { "ATAN", "atan" },
// { "ATAN2", "atan2" },
{ "CEILING", "ceil" },
// { "COS", "cos" },
// { "COT", "cot" },
// { "DEGREES", "degrees" },
// { "EXP", "exp" },
// { "FLOOR", "floor" },
{ "LOG", "ln" },
{ "LOG10", "log" },
// { "MOD", "mod" },
// { "PI", "pi" },
{ "POWER", "pow" },
// { "RADIANS", "radians" },
{ "RAND", "random" },
// { "ROUND", "round" },
// { "SIGN", "sign" },
// { "SIN", "sin" },
// { "SQRT", "sqrt" },
// { "TAN", "tan" },
// { "TRUNCATE", "truncate" },
// { "CURDATE", "curdate" },
// { "CURTIME", "curtime" },
// { "DAYNAME", "dayname" },
// { "DAYOFMONTH", "dayofmonth" },
// { "DAYOFWEEK", "dayofweek" },
// { "DAYOFYEAR", "dayofyear" },
// { "HOUR", "hour" },
// { "MINUTE", "minute" },
// { "MONTH", "month" },
// { "MONTHNAME", "monthname" },
// { "NOW", "now" },
// { "QUARTER", "quarter" },
// { "SECOND", "second" },
// { "WEEK", "week" },
// { "YEAR", "year" },
// { "DATABASE", "database" },
{ "IFNULL", "coalesce" },
{ "USER", "odbc_user" },
{ 0, 0 }
};
@ -584,7 +641,7 @@ int
copy_statement_with_parameters(StatementClass *stmt)
{
static char *func="copy_statement_with_parameters";
unsigned int opos, npos;
unsigned int opos, npos, oldstmtlen;
char param_string[128], tmp[256], cbuf[TEXT_FIELD_SIZE+5];
int param_number;
Int2 param_ctype, param_sqltype;
@ -629,14 +686,17 @@ int lobj_fd, retval;
param_number = -1;
for (opos = 0; opos < strlen(old_statement); opos++) {
oldstmtlen = strlen(old_statement);
for (opos = 0; opos < oldstmtlen; opos++) {
// Squeeze carriage-returns/linfeed pairs to linefeed only
if (old_statement[opos] == '\r' && opos+1<strlen(old_statement) && old_statement[opos+1] == '\n') {
if (old_statement[opos] == '\r' && opos+1 < oldstmtlen &&
old_statement[opos+1] == '\n') {
continue;
}
// Handle literals (date, time, timestamp)
// Handle literals (date, time, timestamp) and ODBC scalar functions
else if (old_statement[opos] == '{') {
char *esc;
char *begin = &old_statement[opos + 1];
@ -1056,37 +1116,69 @@ int i;
return NULL;
}
// This function returns a pointer to static memory!
/* convert_escape()
* This function returns a pointer to static memory!
*/
char *
convert_escape(char *value)
{
char key[32], val[256];
static char escape[1024];
char func[32], the_rest[1024];
char *mapFunc;
char key[33];
sscanf(value, "%s %[^\r]", key, val);
/* Separate off the key, skipping leading and trailing whitespace */
while ((*value != '\0') && isspace(*value)) value++;
sscanf(value, "%32s", key);
while ((*value != '\0') && (! isspace(*value))) value++;
while ((*value != '\0') && isspace(*value)) value++;
mylog("convert_escape: key='%s', val='%s'\n", key, val);
mylog("convert_escape: key='%s', val='%s'\n", key, value);
if ( ! strcmp(key, "d") ||
! strcmp(key, "t") ||
! strcmp(key, "ts")) {
strcpy(escape, val);
if ( (strcmp(key, "d") == 0) ||
(strcmp(key, "t") == 0) ||
(strcmp(key, "ts") == 0)) {
/* Literal; return the escape part as-is */
strncpy(escape, value, sizeof(escape)-1);
}
else if ( ! strcmp(key, "fn")) {
sscanf(val, "%[^(]%[^\r]", func, the_rest);
mapFunc = mapFunction(func);
if ( ! mapFunc)
return NULL;
else {
else if (strcmp(key, "fn") == 0) {
/* Function invocation
* Separate off the func name,
* skipping trailing whitespace.
*/
char *funcEnd = value;
char svchar;
char *mapFunc;
while ((*funcEnd != '\0') && (*funcEnd != '(') &&
(! isspace(*funcEnd))) funcEnd++;
svchar = *funcEnd;
*funcEnd = '\0';
sscanf(value, "%32s", key);
*funcEnd = svchar;
while ((*funcEnd != '\0') && isspace(*funcEnd)) funcEnd++;
/* We expect left parenthensis here,
* else return fn body as-is since it is
* one of those "function constants".
*/
if (*funcEnd != '(') {
strncpy(escape, value, sizeof(escape)-1);
return escape;
}
mapFunc = mapFunction(key);
/* We could have mapFunction() return key if not in table...
* - thomas 2000-04-03
*/
if (mapFunc == NULL) {
/* If unrecognized function name, return fn body as-is */
strncpy(escape, value, sizeof(escape)-1);
return escape;
}
/* copy mapped name and remaining input string */
strcpy(escape, mapFunc);
strcat(escape, the_rest);
}
strncat(escape, funcEnd, sizeof(escape)-strlen(mapFunc));
}
else {
/* Bogus key, leave untranslated */
return NULL;
}