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");
