Author: turnstep
Date: Mon May 18 18:48:10 2009
New Revision: 12781

Modified:
   DBD-Pg/trunk/quote.c
   DBD-Pg/trunk/quote.h
   DBD-Pg/trunk/t/12placeholders.t
   DBD-Pg/trunk/types.c

Log:
More work on fixing up the quoting issues.
Mostly done: quote_int, quote_float, quote_name


Modified: DBD-Pg/trunk/quote.c
==============================================================================
--- DBD-Pg/trunk/quote.c        (original)
+++ DBD-Pg/trunk/quote.c        Mon May 18 18:48:10 2009
@@ -286,24 +286,26 @@
 {
        dTHX;
        char * result;
-       double val;
+       char * endpoint;
+       float val;
 
        /*
-         We do minimal checking here, and let Postgres do the heavy lifting 
-         Out job is to simply filter out bad characters
+         We let strtof do the heavy lifting here, despite it having some 
+         issues according to the PG source
        */
 
-       while (*string != '\0' && isspace((unsigned char) *string))
-               *string++;
+       /* Empty string is always an error. Here for dumb compilers. */
+       if (len<1)
+               croak("Invalid number");
 
        errno = 0;
-       val = strtod(string, &result);
+       val = strtof(string, &endpoint);
 
-       if (result == string || errno != 0) {
-               /* Allow exactly three strings, otherwise bail */
-               if (0 != strncasecmp(string, "NaN", 3)
-                       && 0 != strncasecmp(string, "Infinity", 8)
-                       && 0 != strncasecmp(string, "-Infinity", 9)
+       if (0!=*endpoint || errno != 0) {
+               /* Just in case the compiler used has a crappy strtof */
+               if (0 != strncasecmp(string, "NaN", 4)
+                       && 0 != strncasecmp(string, "Infinity", 9)
+                       && 0 != strncasecmp(string, "-Infinity", 10)
                        ) {
                        croak("Invalid number");
                }
@@ -320,17 +322,67 @@
 {
        dTHX;
        char * result;
+       const char *ptr;
+       int nquotes = 0;
+       int x;
+       bool safe;
+
+       /* We throw double quotes around the whole thing, if:
+          1. It starts with anything other than [a-z_]
+          OR
+          2. It has characters other than [a-z_0-9]
+          OR
+          3. It is a reserved word (e.g. `user`)
+       */
 
-       croak ("Not handled yet");
+       /* 1. It starts with anything other than [a-z_] */
+       safe = ((string[0] >= 'a' && string[0] <= 'z') || '_' == string[0]);
 
-       New(0, result, len+1, char);
-       strcpy(result,string);
-       *retlen = len;
+       /* 2. It has characters other than [a-z_0-9] (also count number of 
quotes) */   
+       for (ptr = string; *ptr; ptr++) {
+
+               char ch = *ptr;
+
+               if (
+                       (ch < 'a' && ch > 'z')
+                       && 
+                       (ch < '0' && ch > '9')
+                       &&
+                       ch != '_') {
+                       safe = DBDPG_FALSE;
+                       if (ch == '"')
+                               nquotes++;
+               }
+       }
+
+       /* 3. Is it a reserved word (e.g. `user`) */
+       if (safe) {
+               if (! is_keyword(string)) {
+                       New(0, result, len+1, char);
+                       strcpy(result,string);
+                       *retlen = len;
+                       return result;
+               }
+       }
+
+       /* Need room for the string, the outer quotes, any inner quotes (which 
get doubled) and \0 */
+       *retlen = len + 2 + nquotes;
+       New(0, result, *retlen + 1, char);
+
+       x=0;
+       result[x++] = '"';
+       for (ptr = string; *ptr; ptr++) {
+               char ch = *ptr;
+               result[x++] = ch;
+               if (ch == '"')
+                       result[x++] = '"';
+       }
+       result[x++] = '"';
+       result[x] = '\0';
 
        return result;
 }
 
-
 void dequote_char(const char *string, STRLEN *retlen, int estring)
 {
        dTHX;
@@ -419,7 +471,6 @@
 }
 
 
-
 void null_dequote(const char *string, STRLEN *retlen, int estring)
 {
        dTHX;
@@ -427,4 +478,499 @@
 
 }
 
+bool is_keyword(const char *string)
+{
+
+       int max_keyword_length = 17;
+       STRLEN len;
+       int i;
+       char word[64];
+
+       len = strlen(string);
+       if (len > max_keyword_length || len > 64) {
+               return DBDPG_FALSE;
+       }
+
+       /* Because of locale issues, we manually downcase A-Z only */
+       for (i = 0; i < len; i++) {
+               char ch = string[i];
+               if (ch >= 'A' && ch <= 'Z')
+                       ch += 'a' - 'A';
+               word[i] = ch;
+       }
+       word[len] = '\0';
+
+       /* Check for each reserved word */
+    if (0==strcmp(word, "abort")) return DBDPG_TRUE;
+    if (0==strcmp(word, "absolute")) return DBDPG_TRUE;
+    if (0==strcmp(word, "access")) return DBDPG_TRUE;
+    if (0==strcmp(word, "action")) return DBDPG_TRUE;
+    if (0==strcmp(word, "add")) return DBDPG_TRUE;
+    if (0==strcmp(word, "admin")) return DBDPG_TRUE;
+    if (0==strcmp(word, "after")) return DBDPG_TRUE;
+    if (0==strcmp(word, "aggregate")) return DBDPG_TRUE;
+    if (0==strcmp(word, "all")) return DBDPG_TRUE;
+    if (0==strcmp(word, "also")) return DBDPG_TRUE;
+    if (0==strcmp(word, "alter")) return DBDPG_TRUE;
+    if (0==strcmp(word, "always")) return DBDPG_TRUE;
+    if (0==strcmp(word, "analyse")) return DBDPG_TRUE;
+    if (0==strcmp(word, "analyze")) return DBDPG_TRUE;
+    if (0==strcmp(word, "and")) return DBDPG_TRUE;
+    if (0==strcmp(word, "any")) return DBDPG_TRUE;
+    if (0==strcmp(word, "array")) return DBDPG_TRUE;
+    if (0==strcmp(word, "as")) return DBDPG_TRUE;
+    if (0==strcmp(word, "asc")) return DBDPG_TRUE;
+    if (0==strcmp(word, "assertion")) return DBDPG_TRUE;
+    if (0==strcmp(word, "assignment")) return DBDPG_TRUE;
+    if (0==strcmp(word, "asymmetric")) return DBDPG_TRUE;
+    if (0==strcmp(word, "at")) return DBDPG_TRUE;
+    if (0==strcmp(word, "authorization")) return DBDPG_TRUE;
+    if (0==strcmp(word, "backward")) return DBDPG_TRUE;
+    if (0==strcmp(word, "before")) return DBDPG_TRUE;
+    if (0==strcmp(word, "begin")) return DBDPG_TRUE;
+    if (0==strcmp(word, "between")) return DBDPG_TRUE;
+    if (0==strcmp(word, "bigint")) return DBDPG_TRUE;
+    if (0==strcmp(word, "binary")) return DBDPG_TRUE;
+    if (0==strcmp(word, "bit")) return DBDPG_TRUE;
+    if (0==strcmp(word, "boolean")) return DBDPG_TRUE;
+    if (0==strcmp(word, "both")) return DBDPG_TRUE;
+    if (0==strcmp(word, "by")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cache")) return DBDPG_TRUE;
+    if (0==strcmp(word, "called")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cascade")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cascaded")) return DBDPG_TRUE;
+    if (0==strcmp(word, "case")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cast")) return DBDPG_TRUE;
+    if (0==strcmp(word, "catalog")) return DBDPG_TRUE;
+    if (0==strcmp(word, "chain")) return DBDPG_TRUE;
+    if (0==strcmp(word, "char")) return DBDPG_TRUE;
+    if (0==strcmp(word, "character")) return DBDPG_TRUE;
+    if (0==strcmp(word, "characteristics")) return DBDPG_TRUE;
+    if (0==strcmp(word, "check")) return DBDPG_TRUE;
+    if (0==strcmp(word, "checkpoint")) return DBDPG_TRUE;
+    if (0==strcmp(word, "class")) return DBDPG_TRUE;
+    if (0==strcmp(word, "close")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cluster")) return DBDPG_TRUE;
+    if (0==strcmp(word, "coalesce")) return DBDPG_TRUE;
+    if (0==strcmp(word, "collate")) return DBDPG_TRUE;
+    if (0==strcmp(word, "column")) return DBDPG_TRUE;
+    if (0==strcmp(word, "comment")) return DBDPG_TRUE;
+    if (0==strcmp(word, "commit")) return DBDPG_TRUE;
+    if (0==strcmp(word, "committed")) return DBDPG_TRUE;
+    if (0==strcmp(word, "concurrently")) return DBDPG_TRUE;
+    if (0==strcmp(word, "configuration")) return DBDPG_TRUE;
+    if (0==strcmp(word, "connection")) return DBDPG_TRUE;
+    if (0==strcmp(word, "constraint")) return DBDPG_TRUE;
+    if (0==strcmp(word, "constraints")) return DBDPG_TRUE;
+    if (0==strcmp(word, "content")) return DBDPG_TRUE;
+    if (0==strcmp(word, "continue")) return DBDPG_TRUE;
+    if (0==strcmp(word, "conversion")) return DBDPG_TRUE;
+    if (0==strcmp(word, "copy")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cost")) return DBDPG_TRUE;
+    if (0==strcmp(word, "create")) return DBDPG_TRUE;
+    if (0==strcmp(word, "createdb")) return DBDPG_TRUE;
+    if (0==strcmp(word, "createrole")) return DBDPG_TRUE;
+    if (0==strcmp(word, "createuser")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cross")) return DBDPG_TRUE;
+    if (0==strcmp(word, "csv")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current_catalog")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current_date")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current_role")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current_schema")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current_time")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current_timestamp")) return DBDPG_TRUE;
+    if (0==strcmp(word, "current_user")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cursor")) return DBDPG_TRUE;
+    if (0==strcmp(word, "cycle")) return DBDPG_TRUE;
+    if (0==strcmp(word, "data")) return DBDPG_TRUE;
+    if (0==strcmp(word, "database")) return DBDPG_TRUE;
+    if (0==strcmp(word, "day")) return DBDPG_TRUE;
+    if (0==strcmp(word, "deallocate")) return DBDPG_TRUE;
+    if (0==strcmp(word, "dec")) return DBDPG_TRUE;
+    if (0==strcmp(word, "decimal")) return DBDPG_TRUE;
+    if (0==strcmp(word, "declare")) return DBDPG_TRUE;
+    if (0==strcmp(word, "default")) return DBDPG_TRUE;
+    if (0==strcmp(word, "defaults")) return DBDPG_TRUE;
+    if (0==strcmp(word, "deferrable")) return DBDPG_TRUE;
+    if (0==strcmp(word, "deferred")) return DBDPG_TRUE;
+    if (0==strcmp(word, "definer")) return DBDPG_TRUE;
+    if (0==strcmp(word, "delete")) return DBDPG_TRUE;
+    if (0==strcmp(word, "delimiter")) return DBDPG_TRUE;
+    if (0==strcmp(word, "delimiters")) return DBDPG_TRUE;
+    if (0==strcmp(word, "desc")) return DBDPG_TRUE;
+    if (0==strcmp(word, "dictionary")) return DBDPG_TRUE;
+    if (0==strcmp(word, "disable")) return DBDPG_TRUE;
+    if (0==strcmp(word, "discard")) return DBDPG_TRUE;
+    if (0==strcmp(word, "distinct")) return DBDPG_TRUE;
+    if (0==strcmp(word, "do")) return DBDPG_TRUE;
+    if (0==strcmp(word, "document")) return DBDPG_TRUE;
+    if (0==strcmp(word, "domain")) return DBDPG_TRUE;
+    if (0==strcmp(word, "double")) return DBDPG_TRUE;
+    if (0==strcmp(word, "drop")) return DBDPG_TRUE;
+    if (0==strcmp(word, "each")) return DBDPG_TRUE;
+    if (0==strcmp(word, "else")) return DBDPG_TRUE;
+    if (0==strcmp(word, "enable")) return DBDPG_TRUE;
+    if (0==strcmp(word, "encoding")) return DBDPG_TRUE;
+    if (0==strcmp(word, "encrypted")) return DBDPG_TRUE;
+    if (0==strcmp(word, "end")) return DBDPG_TRUE;
+    if (0==strcmp(word, "enum")) return DBDPG_TRUE;
+    if (0==strcmp(word, "escape")) return DBDPG_TRUE;
+    if (0==strcmp(word, "except")) return DBDPG_TRUE;
+    if (0==strcmp(word, "excluding")) return DBDPG_TRUE;
+    if (0==strcmp(word, "exclusive")) return DBDPG_TRUE;
+    if (0==strcmp(word, "execute")) return DBDPG_TRUE;
+    if (0==strcmp(word, "exists")) return DBDPG_TRUE;
+    if (0==strcmp(word, "explain")) return DBDPG_TRUE;
+    if (0==strcmp(word, "external")) return DBDPG_TRUE;
+    if (0==strcmp(word, "extract")) return DBDPG_TRUE;
+    if (0==strcmp(word, "false")) return DBDPG_TRUE;
+    if (0==strcmp(word, "family")) return DBDPG_TRUE;
+    if (0==strcmp(word, "fetch")) return DBDPG_TRUE;
+    if (0==strcmp(word, "first")) return DBDPG_TRUE;
+    if (0==strcmp(word, "float")) return DBDPG_TRUE;
+    if (0==strcmp(word, "following")) return DBDPG_TRUE;
+    if (0==strcmp(word, "for")) return DBDPG_TRUE;
+    if (0==strcmp(word, "force")) return DBDPG_TRUE;
+    if (0==strcmp(word, "foreign")) return DBDPG_TRUE;
+    if (0==strcmp(word, "forward")) return DBDPG_TRUE;
+    if (0==strcmp(word, "freeze")) return DBDPG_TRUE;
+    if (0==strcmp(word, "from")) return DBDPG_TRUE;
+    if (0==strcmp(word, "full")) return DBDPG_TRUE;
+    if (0==strcmp(word, "function")) return DBDPG_TRUE;
+    if (0==strcmp(word, "global")) return DBDPG_TRUE;
+    if (0==strcmp(word, "grant")) return DBDPG_TRUE;
+    if (0==strcmp(word, "granted")) return DBDPG_TRUE;
+    if (0==strcmp(word, "greatest")) return DBDPG_TRUE;
+    if (0==strcmp(word, "group")) return DBDPG_TRUE;
+    if (0==strcmp(word, "handler")) return DBDPG_TRUE;
+    if (0==strcmp(word, "having")) return DBDPG_TRUE;
+    if (0==strcmp(word, "header")) return DBDPG_TRUE;
+    if (0==strcmp(word, "hold")) return DBDPG_TRUE;
+    if (0==strcmp(word, "hour")) return DBDPG_TRUE;
+    if (0==strcmp(word, "identity")) return DBDPG_TRUE;
+    if (0==strcmp(word, "if")) return DBDPG_TRUE;
+    if (0==strcmp(word, "ilike")) return DBDPG_TRUE;
+    if (0==strcmp(word, "immediate")) return DBDPG_TRUE;
+    if (0==strcmp(word, "immutable")) return DBDPG_TRUE;
+    if (0==strcmp(word, "implicit")) return DBDPG_TRUE;
+    if (0==strcmp(word, "in")) return DBDPG_TRUE;
+    if (0==strcmp(word, "including")) return DBDPG_TRUE;
+    if (0==strcmp(word, "increment")) return DBDPG_TRUE;
+    if (0==strcmp(word, "index")) return DBDPG_TRUE;
+    if (0==strcmp(word, "indexes")) return DBDPG_TRUE;
+    if (0==strcmp(word, "inherit")) return DBDPG_TRUE;
+    if (0==strcmp(word, "inherits")) return DBDPG_TRUE;
+    if (0==strcmp(word, "initially")) return DBDPG_TRUE;
+    if (0==strcmp(word, "inner")) return DBDPG_TRUE;
+    if (0==strcmp(word, "inout")) return DBDPG_TRUE;
+    if (0==strcmp(word, "input")) return DBDPG_TRUE;
+    if (0==strcmp(word, "insensitive")) return DBDPG_TRUE;
+    if (0==strcmp(word, "insert")) return DBDPG_TRUE;
+    if (0==strcmp(word, "instead")) return DBDPG_TRUE;
+    if (0==strcmp(word, "int")) return DBDPG_TRUE;
+    if (0==strcmp(word, "integer")) return DBDPG_TRUE;
+    if (0==strcmp(word, "intersect")) return DBDPG_TRUE;
+    if (0==strcmp(word, "interval")) return DBDPG_TRUE;
+    if (0==strcmp(word, "into")) return DBDPG_TRUE;
+    if (0==strcmp(word, "invoker")) return DBDPG_TRUE;
+    if (0==strcmp(word, "is")) return DBDPG_TRUE;
+    if (0==strcmp(word, "isnull")) return DBDPG_TRUE;
+    if (0==strcmp(word, "isolation")) return DBDPG_TRUE;
+    if (0==strcmp(word, "join")) return DBDPG_TRUE;
+    if (0==strcmp(word, "key")) return DBDPG_TRUE;
+    if (0==strcmp(word, "lancompiler")) return DBDPG_TRUE;
+    if (0==strcmp(word, "language")) return DBDPG_TRUE;
+    if (0==strcmp(word, "large")) return DBDPG_TRUE;
+    if (0==strcmp(word, "last")) return DBDPG_TRUE;
+    if (0==strcmp(word, "lc_collate")) return DBDPG_TRUE;
+    if (0==strcmp(word, "lc_ctype")) return DBDPG_TRUE;
+    if (0==strcmp(word, "leading")) return DBDPG_TRUE;
+    if (0==strcmp(word, "least")) return DBDPG_TRUE;
+    if (0==strcmp(word, "left")) return DBDPG_TRUE;
+    if (0==strcmp(word, "level")) return DBDPG_TRUE;
+    if (0==strcmp(word, "like")) return DBDPG_TRUE;
+    if (0==strcmp(word, "limit")) return DBDPG_TRUE;
+    if (0==strcmp(word, "listen")) return DBDPG_TRUE;
+    if (0==strcmp(word, "load")) return DBDPG_TRUE;
+    if (0==strcmp(word, "local")) return DBDPG_TRUE;
+    if (0==strcmp(word, "localtime")) return DBDPG_TRUE;
+    if (0==strcmp(word, "localtimestamp")) return DBDPG_TRUE;
+    if (0==strcmp(word, "location")) return DBDPG_TRUE;
+    if (0==strcmp(word, "lock")) return DBDPG_TRUE;
+    if (0==strcmp(word, "login")) return DBDPG_TRUE;
+    if (0==strcmp(word, "mapping")) return DBDPG_TRUE;
+    if (0==strcmp(word, "match")) return DBDPG_TRUE;
+    if (0==strcmp(word, "maxvalue")) return DBDPG_TRUE;
+    if (0==strcmp(word, "minute")) return DBDPG_TRUE;
+    if (0==strcmp(word, "minvalue")) return DBDPG_TRUE;
+    if (0==strcmp(word, "mode")) return DBDPG_TRUE;
+    if (0==strcmp(word, "month")) return DBDPG_TRUE;
+    if (0==strcmp(word, "move")) return DBDPG_TRUE;
+    if (0==strcmp(word, "name")) return DBDPG_TRUE;
+    if (0==strcmp(word, "names")) return DBDPG_TRUE;
+    if (0==strcmp(word, "national")) return DBDPG_TRUE;
+    if (0==strcmp(word, "natural")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nchar")) return DBDPG_TRUE;
+    if (0==strcmp(word, "new")) return DBDPG_TRUE;
+    if (0==strcmp(word, "next")) return DBDPG_TRUE;
+    if (0==strcmp(word, "no")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nocreatedb")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nocreaterole")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nocreateuser")) return DBDPG_TRUE;
+    if (0==strcmp(word, "noinherit")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nologin")) return DBDPG_TRUE;
+    if (0==strcmp(word, "none")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nosuperuser")) return DBDPG_TRUE;
+    if (0==strcmp(word, "not")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nothing")) return DBDPG_TRUE;
+    if (0==strcmp(word, "notify")) return DBDPG_TRUE;
+    if (0==strcmp(word, "notnull")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nowait")) return DBDPG_TRUE;
+    if (0==strcmp(word, "null")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nullif")) return DBDPG_TRUE;
+    if (0==strcmp(word, "nulls")) return DBDPG_TRUE;
+    if (0==strcmp(word, "numeric")) return DBDPG_TRUE;
+    if (0==strcmp(word, "object")) return DBDPG_TRUE;
+    if (0==strcmp(word, "of")) return DBDPG_TRUE;
+    if (0==strcmp(word, "off")) return DBDPG_TRUE;
+    if (0==strcmp(word, "offset")) return DBDPG_TRUE;
+    if (0==strcmp(word, "oids")) return DBDPG_TRUE;
+    if (0==strcmp(word, "old")) return DBDPG_TRUE;
+    if (0==strcmp(word, "on")) return DBDPG_TRUE;
+    if (0==strcmp(word, "only")) return DBDPG_TRUE;
+    if (0==strcmp(word, "operator")) return DBDPG_TRUE;
+    if (0==strcmp(word, "option")) return DBDPG_TRUE;
+    if (0==strcmp(word, "options")) return DBDPG_TRUE;
+    if (0==strcmp(word, "or")) return DBDPG_TRUE;
+    if (0==strcmp(word, "order")) return DBDPG_TRUE;
+    if (0==strcmp(word, "out")) return DBDPG_TRUE;
+    if (0==strcmp(word, "outer")) return DBDPG_TRUE;
+    if (0==strcmp(word, "over")) return DBDPG_TRUE;
+    if (0==strcmp(word, "overlaps")) return DBDPG_TRUE;
+    if (0==strcmp(word, "overlay")) return DBDPG_TRUE;
+    if (0==strcmp(word, "owned")) return DBDPG_TRUE;
+    if (0==strcmp(word, "owner")) return DBDPG_TRUE;
+    if (0==strcmp(word, "parser")) return DBDPG_TRUE;
+    if (0==strcmp(word, "partial")) return DBDPG_TRUE;
+    if (0==strcmp(word, "partition")) return DBDPG_TRUE;
+    if (0==strcmp(word, "password")) return DBDPG_TRUE;
+    if (0==strcmp(word, "placing")) return DBDPG_TRUE;
+    if (0==strcmp(word, "plans")) return DBDPG_TRUE;
+    if (0==strcmp(word, "position")) return DBDPG_TRUE;
+    if (0==strcmp(word, "preceding")) return DBDPG_TRUE;
+    if (0==strcmp(word, "precision")) return DBDPG_TRUE;
+    if (0==strcmp(word, "prepare")) return DBDPG_TRUE;
+    if (0==strcmp(word, "prepared")) return DBDPG_TRUE;
+    if (0==strcmp(word, "preserve")) return DBDPG_TRUE;
+    if (0==strcmp(word, "primary")) return DBDPG_TRUE;
+    if (0==strcmp(word, "prior")) return DBDPG_TRUE;
+    if (0==strcmp(word, "privileges")) return DBDPG_TRUE;
+    if (0==strcmp(word, "procedural")) return DBDPG_TRUE;
+    if (0==strcmp(word, "procedure")) return DBDPG_TRUE;
+    if (0==strcmp(word, "quote")) return DBDPG_TRUE;
+    if (0==strcmp(word, "range")) return DBDPG_TRUE;
+    if (0==strcmp(word, "read")) return DBDPG_TRUE;
+    if (0==strcmp(word, "real")) return DBDPG_TRUE;
+    if (0==strcmp(word, "reassign")) return DBDPG_TRUE;
+    if (0==strcmp(word, "recheck")) return DBDPG_TRUE;
+    if (0==strcmp(word, "recursive")) return DBDPG_TRUE;
+    if (0==strcmp(word, "references")) return DBDPG_TRUE;
+    if (0==strcmp(word, "reindex")) return DBDPG_TRUE;
+    if (0==strcmp(word, "relative")) return DBDPG_TRUE;
+    if (0==strcmp(word, "release")) return DBDPG_TRUE;
+    if (0==strcmp(word, "rename")) return DBDPG_TRUE;
+    if (0==strcmp(word, "repeatable")) return DBDPG_TRUE;
+    if (0==strcmp(word, "replace")) return DBDPG_TRUE;
+    if (0==strcmp(word, "replica")) return DBDPG_TRUE;
+    if (0==strcmp(word, "reset")) return DBDPG_TRUE;
+    if (0==strcmp(word, "restart")) return DBDPG_TRUE;
+    if (0==strcmp(word, "restrict")) return DBDPG_TRUE;
+    if (0==strcmp(word, "returning")) return DBDPG_TRUE;
+    if (0==strcmp(word, "returns")) return DBDPG_TRUE;
+    if (0==strcmp(word, "revoke")) return DBDPG_TRUE;
+    if (0==strcmp(word, "right")) return DBDPG_TRUE;
+    if (0==strcmp(word, "role")) return DBDPG_TRUE;
+    if (0==strcmp(word, "rollback")) return DBDPG_TRUE;
+    if (0==strcmp(word, "row")) return DBDPG_TRUE;
+    if (0==strcmp(word, "rows")) return DBDPG_TRUE;
+    if (0==strcmp(word, "rule")) return DBDPG_TRUE;
+    if (0==strcmp(word, "savepoint")) return DBDPG_TRUE;
+    if (0==strcmp(word, "schema")) return DBDPG_TRUE;
+    if (0==strcmp(word, "scroll")) return DBDPG_TRUE;
+    if (0==strcmp(word, "search")) return DBDPG_TRUE;
+    if (0==strcmp(word, "second")) return DBDPG_TRUE;
+    if (0==strcmp(word, "security")) return DBDPG_TRUE;
+    if (0==strcmp(word, "select")) return DBDPG_TRUE;
+    if (0==strcmp(word, "sequence")) return DBDPG_TRUE;
+    if (0==strcmp(word, "serializable")) return DBDPG_TRUE;
+    if (0==strcmp(word, "server")) return DBDPG_TRUE;
+    if (0==strcmp(word, "session")) return DBDPG_TRUE;
+    if (0==strcmp(word, "session_user")) return DBDPG_TRUE;
+    if (0==strcmp(word, "set")) return DBDPG_TRUE;
+    if (0==strcmp(word, "setof")) return DBDPG_TRUE;
+    if (0==strcmp(word, "share")) return DBDPG_TRUE;
+    if (0==strcmp(word, "show")) return DBDPG_TRUE;
+    if (0==strcmp(word, "similar")) return DBDPG_TRUE;
+    if (0==strcmp(word, "simple")) return DBDPG_TRUE;
+    if (0==strcmp(word, "smallint")) return DBDPG_TRUE;
+    if (0==strcmp(word, "some")) return DBDPG_TRUE;
+    if (0==strcmp(word, "stable")) return DBDPG_TRUE;
+    if (0==strcmp(word, "standalone")) return DBDPG_TRUE;
+    if (0==strcmp(word, "start")) return DBDPG_TRUE;
+    if (0==strcmp(word, "statement")) return DBDPG_TRUE;
+    if (0==strcmp(word, "statistics")) return DBDPG_TRUE;
+    if (0==strcmp(word, "stdin")) return DBDPG_TRUE;
+    if (0==strcmp(word, "stdout")) return DBDPG_TRUE;
+    if (0==strcmp(word, "storage")) return DBDPG_TRUE;
+    if (0==strcmp(word, "strict")) return DBDPG_TRUE;
+    if (0==strcmp(word, "strip")) return DBDPG_TRUE;
+    if (0==strcmp(word, "substring")) return DBDPG_TRUE;
+    if (0==strcmp(word, "superuser")) return DBDPG_TRUE;
+    if (0==strcmp(word, "symmetric")) return DBDPG_TRUE;
+    if (0==strcmp(word, "sysid")) return DBDPG_TRUE;
+    if (0==strcmp(word, "system")) return DBDPG_TRUE;
+    if (0==strcmp(word, "table")) return DBDPG_TRUE;
+    if (0==strcmp(word, "tablespace")) return DBDPG_TRUE;
+    if (0==strcmp(word, "temp")) return DBDPG_TRUE;
+    if (0==strcmp(word, "template")) return DBDPG_TRUE;
+    if (0==strcmp(word, "temporary")) return DBDPG_TRUE;
+    if (0==strcmp(word, "text")) return DBDPG_TRUE;
+    if (0==strcmp(word, "then")) return DBDPG_TRUE;
+    if (0==strcmp(word, "time")) return DBDPG_TRUE;
+    if (0==strcmp(word, "timestamp")) return DBDPG_TRUE;
+    if (0==strcmp(word, "to")) return DBDPG_TRUE;
+    if (0==strcmp(word, "trailing")) return DBDPG_TRUE;
+    if (0==strcmp(word, "transaction")) return DBDPG_TRUE;
+    if (0==strcmp(word, "treat")) return DBDPG_TRUE;
+    if (0==strcmp(word, "trigger")) return DBDPG_TRUE;
+    if (0==strcmp(word, "trim")) return DBDPG_TRUE;
+    if (0==strcmp(word, "true")) return DBDPG_TRUE;
+    if (0==strcmp(word, "truncate")) return DBDPG_TRUE;
+    if (0==strcmp(word, "trusted")) return DBDPG_TRUE;
+    if (0==strcmp(word, "type")) return DBDPG_TRUE;
+    if (0==strcmp(word, "unbounded")) return DBDPG_TRUE;
+    if (0==strcmp(word, "uncommitted")) return DBDPG_TRUE;
+    if (0==strcmp(word, "unencrypted")) return DBDPG_TRUE;
+    if (0==strcmp(word, "union")) return DBDPG_TRUE;
+    if (0==strcmp(word, "unique")) return DBDPG_TRUE;
+    if (0==strcmp(word, "unknown")) return DBDPG_TRUE;
+    if (0==strcmp(word, "unlisten")) return DBDPG_TRUE;
+    if (0==strcmp(word, "until")) return DBDPG_TRUE;
+    if (0==strcmp(word, "update")) return DBDPG_TRUE;
+    if (0==strcmp(word, "user")) return DBDPG_TRUE;
+    if (0==strcmp(word, "using")) return DBDPG_TRUE;
+    if (0==strcmp(word, "vacuum")) return DBDPG_TRUE;
+    if (0==strcmp(word, "valid")) return DBDPG_TRUE;
+    if (0==strcmp(word, "validator")) return DBDPG_TRUE;
+    if (0==strcmp(word, "value")) return DBDPG_TRUE;
+    if (0==strcmp(word, "values")) return DBDPG_TRUE;
+    if (0==strcmp(word, "varchar")) return DBDPG_TRUE;
+    if (0==strcmp(word, "variadic")) return DBDPG_TRUE;
+    if (0==strcmp(word, "varying")) return DBDPG_TRUE;
+    if (0==strcmp(word, "verbose")) return DBDPG_TRUE;
+    if (0==strcmp(word, "version")) return DBDPG_TRUE;
+    if (0==strcmp(word, "view")) return DBDPG_TRUE;
+    if (0==strcmp(word, "volatile")) return DBDPG_TRUE;
+    if (0==strcmp(word, "when")) return DBDPG_TRUE;
+    if (0==strcmp(word, "where")) return DBDPG_TRUE;
+    if (0==strcmp(word, "whitespace")) return DBDPG_TRUE;
+    if (0==strcmp(word, "window")) return DBDPG_TRUE;
+    if (0==strcmp(word, "with")) return DBDPG_TRUE;
+    if (0==strcmp(word, "without")) return DBDPG_TRUE;
+    if (0==strcmp(word, "work")) return DBDPG_TRUE;
+    if (0==strcmp(word, "wrapper")) return DBDPG_TRUE;
+    if (0==strcmp(word, "write")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xml")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlattributes")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlconcat")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlelement")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlforest")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlparse")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlpi")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlroot")) return DBDPG_TRUE;
+    if (0==strcmp(word, "xmlserialize")) return DBDPG_TRUE;
+    if (0==strcmp(word, "year")) return DBDPG_TRUE;
+    if (0==strcmp(word, "yes")) return DBDPG_TRUE;
+    if (0==strcmp(word, "zone")) return DBDPG_TRUE;
+
+       /* We made it! */
+
+       return DBDPG_FALSE;
+
+}
+
 /* end of quote.c */
+
+/*
+#!perl
+
+## Autogenerate the list of reserved keywords
+
+## You should only run this if you are developing DBD::Pg and 
+## understand what this script does
+
+## Usage: perl -x $0 "path-to-pgsql-source"
+
+use strict;
+use warnings;
+
+my $arg = shift || die "Usage: $0 path-to-pgsql-source\n";
+
+-d $arg or die qq{Sorry, but "$arg" is not a directory!\n};
+
+my $file = "$arg/src/include/parser/kwlist.h";
+
+open my $fh, '<', $file or die qq{Could not open file "$file": $!\n};
+my @word;
+my $maxlen = 10;
+while (<$fh>) {
+  next unless /^PG_KEYWORD\("(.+?)"/;
+  ## We don't care what type of word it is - when in doubt, quote it!
+  my $word = $1;
+  push @word => $word;
+  $maxlen = length $word if length $word > $maxlen;
+}
+close $fh or die qq{Could not close "$file": $!\n};
+
+my $tempfile = 'quote.c.tmp';
+open my $fh2, '>', $tempfile or die qq{Could not open "$tempfile": $!\n};
+seek(DATA,0,0);
+my $gotlist = 0;
+while (<DATA>) {
+  s/(int max_keyword_length =) \d+/$1 $maxlen/;
+  if (!$gotlist) {
+    if (/Check for each reserved word/) {
+      $gotlist = 1;
+      print $fh2 $_;
+      for my $word (@word) {
+        print $fh2 qq{    if (0==strcmp(word, "$word")) return DBDPG_TRUE;\n};
+      }
+      print $fh2 "\n";
+      next;
+    }
+  }
+  elsif (1==$gotlist) {
+    if (/We made it/) {
+      $gotlist = 2;
+    }
+    else {
+      next;
+    }
+  }
+
+
+  print $fh2 $_;
+}
+
+close $fh2 or die qq{Could not close "$tempfile": $!\n};
+
+my $ofile = 'quote.c';
+system("mv $tempfile $ofile");
+print "Wrote $ofile\n";
+exit;
+
+__END__
+
+ */
+

Modified: DBD-Pg/trunk/quote.h
==============================================================================
--- DBD-Pg/trunk/quote.h        (original)
+++ DBD-Pg/trunk/quote.h        Mon May 18 18:48:10 2009
@@ -17,3 +17,4 @@
 void dequote_sql_binary(char *string, STRLEN *retlen, int estring);
 void dequote_bool(char *string, STRLEN *retlen, int estring);
 void null_dequote(const char *string, STRLEN *retlen, int estring);
+bool is_keyword(const char *string);

Modified: DBD-Pg/trunk/t/12placeholders.t
==============================================================================
--- DBD-Pg/trunk/t/12placeholders.t     (original)
+++ DBD-Pg/trunk/t/12placeholders.t     Mon May 18 18:48:10 2009
@@ -8,6 +8,7 @@
 use Test::More;
 use lib 't','.';
 use DBI qw/:sql_types/;
+use DBD::Pg qw/:pg_types/;
 require 'dbdpg_test_setup.pl';
 select(($|=1,select(STDERR),$|=1)[1]);
 
@@ -16,7 +17,7 @@
 if (! defined $dbh) {
        plan skip_all => 'Connection to database failed, cannot continue 
testing';
 }
-plan tests => 45;
+plan tests => 129;
 
 my $t='Connect to database for placeholder testing';
 isnt ($dbh, undef, $t);
@@ -309,28 +310,57 @@
        is ($@, q{}, $t);
 }
 
+
+$t='Valid integer works when quoting with SQL_INTEGER';
 my $val;
 $val = $dbh->quote('123', SQL_INTEGER);
-is ($val,123, 'GO?');
+is ($val, 123, $t);
 
+$t='Invalid integer fails to pass through when quoting with SQL_INTEGER';
+$val = -1;
 eval {
        $val = $dbh->quote('123abc', SQL_INTEGER);
 };
-like ($@, qr{Invalid integer}, 'Invalid integer fails to pass through');
+like ($@, qr{Invalid integer}, $t);
+is($val, -1, $t);
 
+my $prefix = 'Valid float value works when quoting with SQL_FLOAT';
+for my $float ('123','0.00','0.234','23.31562', 
'1.23e04','6.54e+02','4e-3','NaN','Infinity','-infinity') {
+       $t = "$prefix (value=$float)";
+       $val = -1;
+       eval { $val = $dbh->quote($float, SQL_FLOAT); };
+       is ($@, q{}, $t);
+       is ($val, $float, $t);
 
-$val = $dbh->quote('123', SQL_INTEGER);
-is ($val,123, 'GO?');
+       next unless $float =~ /\w/;
 
-eval {
-       $val = $dbh->quote('123abc', SQL_FLOAT);
-};
-like ($@, qr{Invalid integer}, 'Invalid integer fails to pass through');
+       my $lcfloat = lc $float;
+       $t = "$prefix (value=$lcfloat)";
+       $val = -1;
+       eval { $val = $dbh->quote($lcfloat, SQL_FLOAT); };
+       is ($@, q{}, $t);
+       is ($val, $lcfloat, $t);
+
+       my $ucfloat = uc $float;
+       $t = "$prefix (value=$ucfloat)";
+       $val = -1;
+       eval { $val = $dbh->quote($ucfloat, SQL_FLOAT); };
+       is ($@, q{}, $t);
+       is ($val, $ucfloat, $t);
+}
 
-exit;
+my $prefix = 'Invalid float value fails when quoting with SQL_FLOAT';
+for my $float ('3abc','123abc','','123e+04e+34','NaNum','-infinitee') {
+       $t = "$prefix (value=$float)";
+       $val = -1;
+       eval { $val = $dbh->quote($float, SQL_FLOAT); };
+       like ($@, qr{Invalid number}, $t);
+       is ($val, -1, $t);
+}
 
 $dbh->rollback();
-## Test placeholerds plus binding
+
+## Test placeholders plus binding
 $t='Bound placeholders enforce data types when not using server side prepares';
 $dbh->trace(0);
 $dbh->{pg_server_prepare} = 0;
@@ -341,6 +371,23 @@
 };
 like ($@, qr{Invalid integer}, 'Invalid integer test 2');
 
+## Test quoting of the "name" type
+$prefix = q{The 'name' data type does correct quoting};
+
+for my $word (qw/User user USER trigger Trigger/) {
+       $t = qq{$prefix for the word "$word"};
+       my $got = $dbh->quote($word, { pg_type => PG_NAME });
+       $expected = qq{"$word"};
+       is($got, $expected, $t);
+}
+
+for my $word (qw/auser userz user-user/) {
+       $t = qq{$prefix for the word "$word"};
+       my $got = $dbh->quote($word, { pg_type => PG_NAME });
+       $expected = qq{$word};
+       is($got, $expected, $t);
+}
+
 ## Begin custom type testing
 
 $dbh->rollback();

Modified: DBD-Pg/trunk/types.c
==============================================================================
--- DBD-Pg/trunk/types.c        (original)
+++ DBD-Pg/trunk/types.c        Mon May 18 18:48:10 2009
@@ -721,7 +721,7 @@
 bpchar   quote_string  dequote_char    SQL_CHAR                  1  0
 cid      quote_string  dequote_string  0                         0  0
 
-## Things that get no quoting at all (e.g. numbers)
+## Things that get special quoting
 int2     quote_int     null_dequote    SQL_SMALLINT|SQL_TINYINT  1  1
 int4     quote_int     null_dequote    SQL_INTEGER               1  1
 int8     quote_int     null_dequote    SQL_BIGINT                1  0

Reply via email to