Augment the function call map logic with code from Tom Lane.
authorThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 4 Apr 2000 01:07:54 +0000 (01:07 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 4 Apr 2000 01:07:54 +0000 (01:07 +0000)
 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.

src/interfaces/odbc/convert.c

index 24906e10ff4cdebc14a6cf38c20a72ef8ed97383..f87b91577997816489aa552a94e435eee1093159 100644 (file)
@@ -58,19 +58,76 @@ 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 */
-char *mapFuncs[][2] = {   
-   { "CONCAT",      "textcat" },
-   { "LCASE",       "lower"   },
-   { "LOCATE",      "strpos"  },
-   { "LENGTH",      "textlen" },
-   { "LTRIM",       "ltrim"   },
-   { "RTRIM",       "rtrim"   },
-   { "SUBSTRING",   "substr"  },
-   { "UCASE",       "upper"   },
-   { "NOW",         "now"     },
-   {    0,             0      }
+/* 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",      "char_length"},
+// { "LTRIM",       "ltrim"      },
+   { "RIGHT",       "rtrunc"     },
+// { "REPEAT",      "repeat"     },
+// { "REPLACE",     "replace"    },
+// { "RTRIM",       "rtrim"      },
+// { "SOUNDEX",     "soundex"    },
+   { "SUBSTRING",   "substr"     },
+   { "UCASE",       "upper"      },
+
+// { "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         }
 };
 
 char *mapFunction(char *func);
@@ -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;
-
-   sscanf(value, "%s %[^\r]", key, val);
+char key[33];
 
-   mylog("convert_escape: key='%s', val='%s'\n", 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++;
 
-   if ( ! strcmp(key, "d") ||
-        ! strcmp(key, "t") ||
-        ! strcmp(key, "ts")) {
+   mylog("convert_escape: key='%s', val='%s'\n", key, value);
 
-       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 {
-           strcpy(escape, mapFunc);
-           strcat(escape, the_rest);
+   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);
+       strncat(escape, funcEnd, sizeof(escape)-strlen(mapFunc));
    }
    else {
+       /* Bogus key, leave untranslated */
        return NULL;
    }