Svami Dhyan Nataraj (shaplov) wrote,
Svami Dhyan Nataraj
shaplov

Postgres: how to add new keyword to SQL grammar

While trying to add something useful into INSERT statement, I wrote more simple example, just to find out how it should work.
I think this might be helpful to people that also want to hack into that area.

Example is very simple, it adds keyword TEST into the definition of attribute list into CREATE INDEX statement, and in ComputeIndexAttrs it says using elog(WARNING ...) whether it found TEST keyword or not.

postgres=# create index  ON mytable (i TEST 'value');
WARNING:  Creating index for column i with TEST value
CREATE INDEX 
postgres=# create index  ON mytable  (i);
WARNING:  TEST is empty
CREATE INDEX


This example is not for production development, it just shows what part of code you should touch in order to modify grammar.

diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index c294c7c..138190e 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1041,6 +1041,14 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 			/* Simple index attribute */
 			HeapTuple	atttuple;
 			Form_pg_attribute attform;
+			
+			if (attribute->test)
+			{
+				elog(WARNING, "Creating index for column %s with TEST %s", attribute->name, attribute->test);
+			} else
+			{
+				elog(WARNING, "TEST is empty");
+			}
 
 			Assert(attribute->expr == NULL);
 			atttuple = SearchSysCacheAttName(relId, attribute->name);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 20e38f0..155070c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2591,6 +2591,7 @@ _copyIndexElem(const IndexElem *from)
 	COPY_NODE_FIELD(opclass);
 	COPY_SCALAR_FIELD(ordering);
 	COPY_SCALAR_FIELD(nulls_ordering);
+	COPY_STRING_FIELD(test);
 
 	return newnode;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 18ec5f0..597ad57 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -316,7 +316,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type 		copy_file_name
 				database_name access_method_clause access_method attr_name
 				name cursor_name file_name
-				index_name opt_index_name cluster_index_specification
+				index_name opt_index_name cluster_index_specification opt_test
 
 %type 	func_name handler_name qual_Op qual_all_Op subquery_Op
 				opt_class opt_inline_handler opt_validator validator_clause
@@ -632,7 +632,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
 	SYMMETRIC SYSID SYSTEM_P
 
-	TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN
+	TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEST TEXT_P THEN
 	TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM TREAT TRIGGER TRIM TRUE_P
 	TRUNCATE TRUSTED TYPE_P TYPES_P
 
@@ -715,6 +715,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %left		'(' ')'
 %left		TYPECAST
 %left		'.'
+
 /*
  * These might seem to be low-precedence, but actually they are not part
  * of the arithmetic hierarchy at all in their use as JOIN operators.
@@ -6707,7 +6708,7 @@ index_params:	index_elem							{ $$ = list_make1($1); }
  * expressions in parens.  For backwards-compatibility reasons, we allow
  * an expression that's just a function call to be written without parens.
  */
-index_elem:	ColId opt_collate opt_class opt_asc_desc opt_nulls_order
+index_elem:	ColId opt_collate opt_class opt_asc_desc opt_nulls_order opt_test
 				{
 					$$ = makeNode(IndexElem);
 					$$->name = $1;
@@ -6717,8 +6718,9 @@ index_elem:	ColId opt_collate opt_class opt_asc_desc opt_nulls_order
 					$$->opclass = $3;
 					$$->ordering = $4;
 					$$->nulls_ordering = $5;
+					$$->test = $6;
 				}
-			| func_expr_windowless opt_collate opt_class opt_asc_desc opt_nulls_order
+			| func_expr_windowless opt_collate opt_class opt_asc_desc opt_nulls_order opt_test
 				{
 					$$ = makeNode(IndexElem);
 					$$->name = NULL;
@@ -6728,8 +6730,9 @@ index_elem:	ColId opt_collate opt_class opt_asc_desc opt_nulls_order
 					$$->opclass = $3;
 					$$->ordering = $4;
 					$$->nulls_ordering = $5;
+					$$->test = $6;
 				}
-			| '(' a_expr ')' opt_collate opt_class opt_asc_desc opt_nulls_order
+			| '(' a_expr ')' opt_collate opt_class opt_asc_desc opt_nulls_order opt_test
 				{
 					$$ = makeNode(IndexElem);
 					$$->name = NULL;
@@ -6739,6 +6742,7 @@ index_elem:	ColId opt_collate opt_class opt_asc_desc opt_nulls_order
 					$$->opclass = $5;
 					$$->ordering = $6;
 					$$->nulls_ordering = $7;
+					$$->test = $8;
 				}
 		;
 
@@ -6761,6 +6765,10 @@ opt_nulls_order: NULLS_LA FIRST_P			{ $$ = SORTBY_NULLS_FIRST; }
 			| /*EMPTY*/						{ $$ = SORTBY_NULLS_DEFAULT; }
 		;
 
+opt_test:	 TEST Sconst							{ $$ = $2; }
+			| /*EMPTY*/								{ $$ = NULL; }
+		;
+
 
 /*****************************************************************************
  *
@@ -14159,6 +14167,7 @@ reserved_keyword:
 			| SOME
 			| SYMMETRIC
 			| TABLE
+			| TEST
 			| THEN
 			| TO
 			| TRAILING
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 714cf15..54e3de8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -638,6 +638,7 @@ typedef struct IndexElem
 	List	   *opclass;		/* name of desired opclass; NIL = default */
 	SortByDir	ordering;		/* ASC/DESC/default */
 	SortByNulls nulls_ordering; /* FIRST/LAST/default */
+	char	   *test;
 } IndexElem;
 
 /*
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 17ffef5..2b7f2fd 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -380,6 +380,7 @@ PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD)
 PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD)
 PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
 PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
+PG_KEYWORD("test", TEST, RESERVED_KEYWORD)
 PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
 PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
Tags: postgres_en
Subscribe

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments