Hi,

The attached patch implements a new function, pg_get_keywords(), which
returns a set of records describing the keywords recognised by the
server. This allows clients such as pgAdmin to get quoting rules
correct, and helps with other tasks such as syntax highlighting where
we need to support multiple server versions.

Example output (edited of course):

postgres=# select * from pg_get_keywords();
       word        |       category
-------------------+-----------------------
 all               | Reserved
 binary            | Type or function name
 xmlserialize      | Column name
 zone              | Unreserved
(372 rows)

I wasn't sure about the best way to describe the categories -
obviously they need to be non-translatable (for client software to
interpret), but human readable is also nice. I'm happy to hear
alternate suggestions.

-- 
Dave Page
EnterpriseDB UK: http://www.enterprisedb.com
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/func.sgml,v
retrieving revision 1.434
diff -c -r1.434 func.sgml
*** doc/src/sgml/func.sgml      28 Apr 2008 14:48:57 -0000      1.434
--- doc/src/sgml/func.sgml      2 May 2008 20:07:47 -0000
***************
*** 10874,10879 ****
--- 10874,10885 ----
        </row>

        <row>
+        
<entry><literal><function>pg_get_keywords</function>()</literal></entry>
+        <entry><type>setof record</type></entry>
+        <entry>list of keywords and their categories</entry>
+       </row>
+
+       <row>
         
<entry><literal><function>pg_my_temp_schema</function>()</literal></entry>
         <entry><type>oid</type></entry>
         <entry>OID of session's temporary schema, or 0 if none</entry>
***************
*** 11009,11014 ****
--- 11015,11032 ----
     </para>

     <indexterm>
+     <primary>pg_get_keywords</primary>
+    </indexterm>
+
+    <para>
+     <function>pg_get_keywords</function> returns a set of records describing
+     the keywords recognized by the server. The <structfield>word</> column
+     contains the keyword, and the <structfield>category</> column contains
+     a description of the category, one of "Unreserved", "Column name",
+     "Type or function name" or "Unreserved".
+    </para>
+
+    <indexterm>
      <primary>pg_my_temp_schema</primary>
     </indexterm>

Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.195
diff -c -r1.195 keywords.c
*** src/backend/parser/keywords.c       27 Mar 2008 03:57:33 -0000      1.195
--- src/backend/parser/keywords.c       2 May 2008 19:32:40 -0000
***************
*** 38,44 ****
   * !!WARNING!!: This list must be sorted by ASCII name, because binary
   *             search is used to locate entries.
   */
! static const ScanKeyword ScanKeywords[] = {
        /* name, value, category */
        {"abort", ABORT_P, UNRESERVED_KEYWORD},
        {"absolute", ABSOLUTE_P, UNRESERVED_KEYWORD},
--- 38,44 ----
   * !!WARNING!!: This list must be sorted by ASCII name, because binary
   *             search is used to locate entries.
   */
! const ScanKeyword ScanKeywords[] = {
        /* name, value, category */
        {"abort", ABORT_P, UNRESERVED_KEYWORD},
        {"absolute", ABSOLUTE_P, UNRESERVED_KEYWORD},
***************
*** 423,428 ****
--- 423,431 ----
        {"zone", ZONE, UNRESERVED_KEYWORD},
  };

+ /* End of ScanKeywords, for use elsewhere */
+ const ScanKeyword *LastScanKeyword = endof(ScanKeywords);
+
  /*
   * ScanKeywordLookup - see if a given word is a keyword
   *
Index: src/backend/utils/adt/misc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/misc.c,v
retrieving revision 1.62
diff -c -r1.62 misc.c
*** src/backend/utils/adt/misc.c        17 Apr 2008 20:56:41 -0000      1.62
--- src/backend/utils/adt/misc.c        2 May 2008 19:50:16 -0000
***************
*** 20,29 ****
--- 20,31 ----
  #include <math.h>

  #include "access/xact.h"
+ #include "catalog/pg_type.h"
  #include "catalog/pg_tablespace.h"
  #include "commands/dbcommands.h"
  #include "funcapi.h"
  #include "miscadmin.h"
+ #include "parser/keywords.h"
  #include "postmaster/syslogger.h"
  #include "storage/fd.h"
  #include "storage/pmsignal.h"
***************
*** 322,324 ****
--- 324,389 ----

        PG_RETURN_VOID();
  }
+
+ /* Function to return the keywords list */
+ extern const ScanKeyword ScanKeywords[];
+ extern const ScanKeyword *LastScanKeyword;
+
+ Datum
+ pg_get_keywords(PG_FUNCTION_ARGS)
+ {
+       FuncCallContext *funcctx;
+
+       if (SRF_IS_FIRSTCALL())
+       {
+               MemoryContext oldcontext;
+               TupleDesc       tupdesc;
+
+               funcctx = SRF_FIRSTCALL_INIT();
+               oldcontext = 
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+               tupdesc = CreateTemplateTupleDesc(2, false);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
+                                                  TEXTOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 2, "category",
+                                                  TEXTOID, -1, 0);
+
+               funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+
+               MemoryContextSwitchTo(oldcontext);
+       }
+
+       funcctx = SRF_PERCALL_SETUP();
+
+       if (&ScanKeywords[funcctx->call_cntr] < LastScanKeyword)
+       {
+               char       *values[2];
+               HeapTuple       tuple;
+
+               values[0] = ScanKeywords[funcctx->call_cntr].name;
+
+               switch (ScanKeywords[funcctx->call_cntr].category)
+               {
+                       case UNRESERVED_KEYWORD:
+                               values[1] = "Unreserved";
+                               break;
+                       case COL_NAME_KEYWORD:
+                               values[1] = "Column name";
+                               break;
+                       case TYPE_FUNC_NAME_KEYWORD:
+                               values[1] = "Type or function name";
+                               break;
+                       case RESERVED_KEYWORD:
+                               values[1] = "Reserved";
+                               break;
+                       default:
+                               values[1] = "Unknown";
+               }
+
+               tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+
+               SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+       }
+
+       SRF_RETURN_DONE(funcctx);
+ }
+
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.494
diff -c -r1.494 pg_proc.h
*** src/include/catalog/pg_proc.h       29 Apr 2008 13:00:22 -0000      1.494
--- src/include/catalog/pg_proc.h       2 May 2008 19:51:12 -0000
***************
*** 3193,3198 ****
--- 3193,3201 ----
  DATA(insert OID = 2626 ( pg_sleep                     PGNSP PGUID 12 1 0 f f 
t f v 1 2278 "701" _null_ _null_ _null_ pg_sleep - _null_ _null_ ));
  DESCR("sleep for the specified time in seconds");

+ DATA(insert OID = 2700 ( pg_get_keywords      PGNSP PGUID 12 10 400 f f t t s 
0 2249 "" "{25,25}" "{o,o}" "{word,category}" pg_get_keywords - _null_ _null_ 
));
+ DESCR("return keyword list");
+
  DATA(insert OID = 2971 (  text                                PGNSP PGUID 12 
1 0 f f t f i 1 25 "16" _null_ _null_ _null_ booltext - _null_ _null_ ));
  DESCR("convert boolean to text");
-- 
Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches

Reply via email to