Hi,

po 4. 2. 2019 v 6:10 odesílatel Michael Paquier <mich...@paquier.xyz>
napsal:

> On Fri, Jan 04, 2019 at 02:17:49PM +0100, Pavel Stehule wrote:
> > It means to write own lexer and preparse source code before I start
> > checking.
> >
> > I think so block level PRAGMA is significantly better solution
>
> Please note that the latest patch is failing to apply, so I have moved
> the patch to next CF, waiting on author.
>

 attached rebased patch

thank you for checking.

Regards

Pavel

--
> Michael
>
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index f8c6435c50..54bfb3f137 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -814,6 +814,49 @@ $$ LANGUAGE plpgsql;
     happen in a plain SQL command.
    </para>
   </sect2>
+
+  <sect2 id="plpgsql-declaration-pragma">
+   <title>Block level PRAGMA</title>
+
+   <para>
+    A <application>PL/pgSQL</application> function supports pragma on block
+    level. Pragma is a compiler directive, that can be used by
+    <application>PL/pgSQL</application> compiler, or by any extensions that
+    can work with <application>PL/pgSQL</application> code.
+   </para>
+
+<synopsis>
+<literal>PRAGMA</literal> <replaceable>name</replaceable>;
+<literal>PRAGMA</literal> <replaceable>name</replaceable> ( <optional> <replaceable>argument_name</replaceable> =&gt; </optional> <replaceable>value</replaceable> );
+</synopsis>
+
+   <para>
+    The pragma can be used for <application>plpgsql_check</application>
+    enabling/disabling code checking or for storing additional information:
+
+<programlisting>
+DECLARE
+  PRAGMA plpgsql_check(off);
+BEGIN
+  -- code inside block will not be checked by plpgsql_check
+  ...
+
+
+DECLARE
+  -- force routine volatility detection
+  PRAGMA plpgsql_check(volatility => volatile);
+  PRAGMA plpgsql_check(temporary_table => 'tmp_tab', '(a int, b int, c int)');
+BEGIN
+  ...
+</programlisting>
+
+    More details are described in related extension's description.
+   </para>
+
+   <para>
+    Unknown pragma is ignored.
+   </para>
+  </sect2>
   </sect1>
 
   <sect1 id="plpgsql-expressions">
diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile
index cc1c2613d3..2aded819f9 100644
--- a/src/pl/plpgsql/src/Makefile
+++ b/src/pl/plpgsql/src/Makefile
@@ -27,7 +27,8 @@ DATA = plpgsql.control plpgsql--1.0.sql plpgsql--unpackaged--1.0.sql
 REGRESS_OPTS = --dbname=$(PL_TESTDB)
 
 REGRESS = plpgsql_call plpgsql_control plpgsql_domain plpgsql_record \
-	plpgsql_cache plpgsql_transaction plpgsql_trigger plpgsql_varprops
+	plpgsql_cache plpgsql_transaction plpgsql_trigger plpgsql_varprops \
+	plpgsql_pragma
 
 # where to find gen_keywordlist.pl and subsidiary files
 TOOLSDIR = $(top_srcdir)/src/tools
diff --git a/src/pl/plpgsql/src/expected/plpgsql_pragma.out b/src/pl/plpgsql/src/expected/plpgsql_pragma.out
new file mode 100644
index 0000000000..ffe5c7664a
--- /dev/null
+++ b/src/pl/plpgsql/src/expected/plpgsql_pragma.out
@@ -0,0 +1,11 @@
+do $$
+DECLARE
+  var int;
+  PRAGMA xxx;
+  PRAGMA do;
+  PRAGMA var; -- name can be any identifier
+  PRAGMA xxx(10, 10.1, 'aaaa', "aaaaa".aaaa, off, on); -- supported types
+  PRAGMA xxx(label => value);
+BEGIN
+END;
+$$;
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 03f7cdce8c..33e6929af9 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -111,6 +111,11 @@ static	PLpgSQL_expr	*read_cursor_args(PLpgSQL_var *cursor,
 static	List			*read_raise_options(void);
 static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 
+/*
+ * local variable for collection pragmas inside one declare block
+ */
+static List		   *pragmas;
+
 %}
 
 %expect 0
@@ -146,6 +151,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 			char *label;
 			int  n_initvars;
 			int  *initvarnos;
+			List *pragmas;
 		}						declhdr;
 		struct
 		{
@@ -166,6 +172,8 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 		PLpgSQL_diag_item		*diagitem;
 		PLpgSQL_stmt_fetch		*fetch;
 		PLpgSQL_case_when		*casewhen;
+		PLpgSQL_pragma			*pragma;
+		PLpgSQL_pragma_arg		*pragma_arg;
 }
 
 %type <declhdr> decl_sect
@@ -221,6 +229,9 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 
 %type <keyword>	unreserved_keyword
 
+%type <list>	pragma_args
+%type <pragma_arg> pragma_arg
+%type <pragma_arg> pragma_val
 
 /*
  * Basic non-keyword token types.  These are hard-wired into the core lexer.
@@ -321,6 +332,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_PG_EXCEPTION_CONTEXT
 %token <keyword>	K_PG_EXCEPTION_DETAIL
 %token <keyword>	K_PG_EXCEPTION_HINT
+%token <keyword>	K_PRAGMA
 %token <keyword>	K_PRINT_STRICT_PARAMS
 %token <keyword>	K_PRIOR
 %token <keyword>	K_QUERY
@@ -418,6 +430,7 @@ pl_block		: decl_sect K_BEGIN proc_sect exception_sect K_END opt_label
 						new->label		= $1.label;
 						new->n_initvars = $1.n_initvars;
 						new->initvarnos = $1.initvarnos;
+						new->pragmas	= $1.pragmas;
 						new->body		= $3;
 						new->exceptions	= $4;
 
@@ -436,6 +449,7 @@ decl_sect		: opt_block_label
 						$$.label	  = $1;
 						$$.n_initvars = 0;
 						$$.initvarnos = NULL;
+						$$.pragmas	  = NIL;
 					}
 				| opt_block_label decl_start
 					{
@@ -443,6 +457,7 @@ decl_sect		: opt_block_label
 						$$.label	  = $1;
 						$$.n_initvars = 0;
 						$$.initvarnos = NULL;
+						$$.pragmas	  = NIL;
 					}
 				| opt_block_label decl_start decl_stmts
 					{
@@ -450,6 +465,9 @@ decl_sect		: opt_block_label
 						$$.label	  = $1;
 						/* Remember variables declared in decl_stmts */
 						$$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
+
+						/* there are nothing special work, use local list only */
+						$$.pragmas = pragmas;
 					}
 				;
 
@@ -579,6 +597,112 @@ decl_statement	: decl_varname decl_const decl_datatype decl_collate decl_notnull
 							new->cursor_explicit_argrow = $5->dno;
 						new->cursor_options = CURSOR_OPT_FAST_PLAN | $2;
 					}
+				| K_PRAGMA any_identifier ';'
+					{
+						PLpgSQL_pragma *new = palloc0(sizeof(PLpgSQL_pragma));
+
+						new->name = $2;
+						new->args = NIL;
+
+						pragmas = lappend(pragmas, new);
+					}
+				| K_PRAGMA any_identifier '(' pragma_args ')' ';'
+					{
+						PLpgSQL_pragma *new = palloc0(sizeof(PLpgSQL_pragma));
+
+						new->name = $2;
+						new->args = $4;
+
+						pragmas = lappend(pragmas, new);
+					}
+				;
+
+pragma_args		: pragma_args ',' pragma_arg
+					{
+						$$ = lappend($1, $3);
+					}
+				| pragma_arg
+					{
+						$$ = list_make1($1);
+					}
+				;
+
+pragma_arg		: pragma_val
+					{
+						$1->argname = NULL;
+						$$ = $1;
+					}
+				| any_identifier EQUALS_GREATER pragma_val
+					{
+						$3->argname = $1;
+						$$ = $3;
+					}
+				;
+
+pragma_val		: T_WORD
+					{
+						PLpgSQL_pragma_arg *new = palloc0(sizeof(PLpgSQL_pragma_arg));
+
+						new->type = PLPGSQL_PRAGMA_ARG_IDENT;
+						new->val.ident = $1.ident;
+						$$ = new;
+					}
+				| unreserved_keyword
+					{
+						PLpgSQL_pragma_arg *new = palloc0(sizeof(PLpgSQL_pragma_arg));
+
+						new->type = PLPGSQL_PRAGMA_ARG_IDENT;
+						new->val.ident = pstrdup($1);
+						$$ = new;
+					}
+				| T_DATUM
+					{
+						PLpgSQL_pragma_arg *new = palloc0(sizeof(PLpgSQL_pragma_arg));
+
+						if ($1.ident)
+						{
+							new->type = PLPGSQL_PRAGMA_ARG_QUAL_IDENT;
+							new->val.idents = $1.idents;
+						}
+						else
+						{
+							new->type = PLPGSQL_PRAGMA_ARG_IDENT;
+							new->val.ident = $1.ident;
+						}
+						$$ = new;
+					}
+				| T_CWORD
+					{
+						PLpgSQL_pragma_arg *new = palloc0(sizeof(PLpgSQL_pragma_arg));
+
+						new->type = PLPGSQL_PRAGMA_ARG_QUAL_IDENT;
+						new->val.idents = $1.idents;
+						$$ = new;
+					}
+				| SCONST
+					{
+						PLpgSQL_pragma_arg *new = palloc0(sizeof(PLpgSQL_pragma_arg));
+
+						new->type = PLPGSQL_PRAGMA_ARG_SCONST;
+						new->val.str = $1;
+						$$ = new;
+					}
+				| FCONST
+					{
+						PLpgSQL_pragma_arg *new = palloc0(sizeof(PLpgSQL_pragma_arg));
+
+						new->type = PLPGSQL_PRAGMA_ARG_FCONST;
+						new->val.fval = atof($1);
+						$$ = new;
+					}
+				| ICONST
+					{
+						PLpgSQL_pragma_arg *new = palloc0(sizeof(PLpgSQL_pragma_arg));
+
+						new->type = PLPGSQL_PRAGMA_ARG_ICONST;
+						new->val.ival = $1;
+						$$ = new;
+					}
 				;
 
 opt_scrollable :
@@ -2422,11 +2546,13 @@ expr_until_loop :
 opt_block_label	:
 					{
 						plpgsql_ns_push(NULL, PLPGSQL_LABEL_BLOCK);
+						pragmas = NIL;
 						$$ = NULL;
 					}
 				| LESS_LESS any_identifier GREATER_GREATER
 					{
 						plpgsql_ns_push($2, PLPGSQL_LABEL_BLOCK);
+						pragmas = NIL;
 						$$ = $2;
 					}
 				;
diff --git a/src/pl/plpgsql/src/pl_reserved_kwlist.h b/src/pl/plpgsql/src/pl_reserved_kwlist.h
index 8425c3ca2e..00383f970b 100644
--- a/src/pl/plpgsql/src/pl_reserved_kwlist.h
+++ b/src/pl/plpgsql/src/pl_reserved_kwlist.h
@@ -44,6 +44,7 @@ PG_KEYWORD("loop", K_LOOP)
 PG_KEYWORD("not", K_NOT)
 PG_KEYWORD("null", K_NULL)
 PG_KEYWORD("or", K_OR)
+PG_KEYWORD("pragma", K_PRAGMA)
 PG_KEYWORD("strict", K_STRICT)
 PG_KEYWORD("then", K_THEN)
 PG_KEYWORD("to", K_TO)
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 0a5fbfa9d6..9eee915cd4 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -499,6 +499,7 @@ typedef struct PLpgSQL_stmt_block
 	int			n_initvars;		/* Length of initvarnos[] */
 	int		   *initvarnos;		/* dnos of variables declared in this block */
 	PLpgSQL_exception_block *exceptions;
+	List	   *pragmas;		/* list of pragmas */
 } PLpgSQL_stmt_block;
 
 /*
@@ -1158,6 +1159,35 @@ typedef struct PLwdatum
 	List	   *idents;			/* valid if composite name */
 } PLwdatum;
 
+typedef enum PLpgSQL_pragma_arg_type
+{
+	PLPGSQL_PRAGMA_ARG_IDENT,
+	PLPGSQL_PRAGMA_ARG_QUAL_IDENT,
+	PLPGSQL_PRAGMA_ARG_SCONST,
+	PLPGSQL_PRAGMA_ARG_FCONST,
+	PLPGSQL_PRAGMA_ARG_ICONST,
+} PLpgSQL_pragma_arg_type;
+
+typedef struct PLpgSQL_pragma_arg
+{
+	char	   *argname;
+	PLpgSQL_pragma_arg_type type;
+	union
+	{
+		char	   *ident;
+		List	   *idents;
+		int			ival;
+		double		fval;
+		char	   *str;
+	} val;
+} PLpgSQL_pragma_arg;
+
+typedef struct PLpgSQL_pragma
+{
+	char	   *name;			/* name of pragma */
+	List	   *args;
+} PLpgSQL_pragma;
+
 /**********************************************************************
  * Global variable declarations
  **********************************************************************/
diff --git a/src/pl/plpgsql/src/sql/plpgsql_pragma.sql b/src/pl/plpgsql/src/sql/plpgsql_pragma.sql
new file mode 100644
index 0000000000..ffe5c7664a
--- /dev/null
+++ b/src/pl/plpgsql/src/sql/plpgsql_pragma.sql
@@ -0,0 +1,11 @@
+do $$
+DECLARE
+  var int;
+  PRAGMA xxx;
+  PRAGMA do;
+  PRAGMA var; -- name can be any identifier
+  PRAGMA xxx(10, 10.1, 'aaaa', "aaaaa".aaaa, off, on); -- supported types
+  PRAGMA xxx(label => value);
+BEGIN
+END;
+$$;

Reply via email to