strict.patch

text/plain

Filename: strict.patch
Type: text/plain
Part: 0
Message: PL/PgSQL STRICT

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
File+
src/pl/plpgsql/src/pl_exec.c 28 0
src/pl/plpgsql/src/pl_funcs.c 1 0
src/pl/plpgsql/src/pl_gram.y 24 0
src/pl/plpgsql/src/plpgsql.h 1 0
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 1500,1508 **** static int
  exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
  {
  	PLpgSQL_expr *expr = stmt->expr;
  
  	(void) exec_run_select(estate, expr, 0, NULL);
! 	exec_set_found(estate, (estate->eval_processed != 0));
  	exec_eval_cleanup(estate);
  
  	return PLPGSQL_RC_OK;
--- 1500,1519 ----
  exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
  {
  	PLpgSQL_expr *expr = stmt->expr;
+ 	uint32 n;
  
  	(void) exec_run_select(estate, expr, 0, NULL);
! 	n = estate->eval_processed;
! 	if (stmt->strict && n == 0)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_NO_DATA_FOUND),
! 				 errmsg("query returned no rows")));
! 	else if (stmt->strict && n > 1)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_TOO_MANY_ROWS),
! 				 errmsg("query returned more than one row")));
! 
! 	exec_set_found(estate, (n != 0));
  	exec_eval_cleanup(estate);
  
  	return PLPGSQL_RC_OK;
***************
*** 3211,3217 **** exec_stmt_execsql(PLpgSQL_execstate *estate,
  	 * forcing completion of a sequential scan.  So don't do it unless we need
  	 * to enforce strictness.
  	 */
! 	if (stmt->into)
  	{
  		if (stmt->strict || stmt->mod_stmt)
  			tcount = 2;
--- 3222,3228 ----
  	 * forcing completion of a sequential scan.  So don't do it unless we need
  	 * to enforce strictness.
  	 */
! 	if (stmt->into || stmt->strict)
  	{
  		if (stmt->strict || stmt->mod_stmt)
  			tcount = 2;
***************
*** 3335,3340 **** exec_stmt_execsql(PLpgSQL_execstate *estate,
--- 3346,3366 ----
  		exec_eval_cleanup(estate);
  		SPI_freetuptable(SPI_tuptable);
  	}
+ 	else if (stmt->strict)
+ 	{
+ 		/*
+ 		 * If a mod stmt specified STRICT, and the query didn't find
+ 		 * exactly one row, throw an error.
+ 		 */
+ 		if (SPI_processed == 0)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_NO_DATA_FOUND),
+ 					 errmsg("query returned no rows")));
+ 		else if (SPI_processed > 1)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_TOO_MANY_ROWS),
+ 					 errmsg("query returned more than one row")));
+ 	}
  	else
  	{
  		/* If the statement returned a tuple table, complain */
*** a/src/pl/plpgsql/src/pl_funcs.c
--- b/src/pl/plpgsql/src/pl_funcs.c
***************
*** 1187,1193 **** static void
  dump_perform(PLpgSQL_stmt_perform *stmt)
  {
  	dump_ind();
! 	printf("PERFORM expr = ");
  	dump_expr(stmt->expr);
  	printf("\n");
  }
--- 1187,1193 ----
  dump_perform(PLpgSQL_stmt_perform *stmt)
  {
  	dump_ind();
! 	printf("PERFORM%s expr = ", stmt->strict ? " STRICT" : "");
  	dump_expr(stmt->expr);
  	printf("\n");
  }
*** a/src/pl/plpgsql/src/pl_gram.y
--- b/src/pl/plpgsql/src/pl_gram.y
***************
*** 178,183 **** static	List			*read_raise_options(void);
--- 178,184 ----
  %type <expr>	expr_until_semi expr_until_rightbracket
  %type <expr>	expr_until_then expr_until_loop opt_expr_until_when
  %type <expr>	opt_exitcond
+ %type <boolean> opt_strict
  
  %type <ival>	assign_var foreach_slice
  %type <var>		cursor_variable
***************
*** 834,847 **** proc_stmt		: pl_block ';'
  						{ $$ = $1; }
  				;
  
! stmt_perform	: K_PERFORM expr_until_semi
  					{
  						PLpgSQL_stmt_perform *new;
  
  						new = palloc0(sizeof(PLpgSQL_stmt_perform));
  						new->cmd_type = PLPGSQL_STMT_PERFORM;
  						new->lineno   = plpgsql_location_to_lineno(@1);
! 						new->expr  = $2;
  
  						$$ = (PLpgSQL_stmt *)new;
  					}
--- 835,849 ----
  						{ $$ = $1; }
  				;
  
! stmt_perform	: K_PERFORM opt_strict expr_until_semi
  					{
  						PLpgSQL_stmt_perform *new;
  
  						new = palloc0(sizeof(PLpgSQL_stmt_perform));
  						new->cmd_type = PLPGSQL_STMT_PERFORM;
  						new->lineno   = plpgsql_location_to_lineno(@1);
! 						new->strict = $2;
! 						new->expr  = $3;
  
  						$$ = (PLpgSQL_stmt *)new;
  					}
***************
*** 2207,2212 **** opt_exitcond	: ';'
--- 2209,2223 ----
  					{ $$ = $2; }
  				;
  
+ opt_strict		:
+ 					{
+ 						$$ = false;
+ 					}
+ 				| K_STRICT
+ 					{
+ 						$$ = true;
+ 					}
+ 
  /*
   * need to allow DATUM because scanner will have tried to resolve as variable
   */
***************
*** 2665,2679 **** make_execsql_stmt(int firsttoken, int location)
  	{
  		prev_tok = tok;
  		tok = yylex();
! 		if (have_into && into_end_loc < 0)
! 			into_end_loc = yylloc;		/* token after the INTO part */
  		if (tok == ';')
  			break;
  		if (tok == 0)
  			yyerror("unexpected end of function definition");
  
  		if (tok == K_INTO && prev_tok != K_INSERT)
  		{
  			if (have_into)
  				yyerror("INTO specified more than once");
  			have_into = true;
--- 2676,2698 ----
  	{
  		prev_tok = tok;
  		tok = yylex();
! 		if ((have_strict || have_into) && into_end_loc < 0)
! 			into_end_loc = yylloc;		/* token after the INTO (or STRICT) part */
  		if (tok == ';')
  			break;
  		if (tok == 0)
  			yyerror("unexpected end of function definition");
  
+ 		if (tok == K_STRICT)
+ 		{
+ 			into_start_loc = yylloc;
+ 			have_strict = true;
+ 		}
+ 
  		if (tok == K_INTO && prev_tok != K_INSERT)
  		{
+ 			if (have_strict)
+ 				yyerror("STRICT must be part of INTO clause of INTO is specified");
  			if (have_into)
  				yyerror("INTO specified more than once");
  			have_into = true;
***************
*** 2686,2692 **** make_execsql_stmt(int firsttoken, int location)
  
  	plpgsql_IdentifierLookup = save_IdentifierLookup;
  
! 	if (have_into)
  	{
  		/*
  		 * Insert an appropriate number of spaces corresponding to the
--- 2705,2711 ----
  
  	plpgsql_IdentifierLookup = save_IdentifierLookup;
  
! 	if (have_strict || have_into)
  	{
  		/*
  		 * Insert an appropriate number of spaces corresponding to the
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
***************
*** 375,380 **** typedef struct
--- 375,381 ----
  {								/* PERFORM statement		*/
  	int			cmd_type;
  	int			lineno;
+ 	bool		strict;
  	PLpgSQL_expr *expr;
  } PLpgSQL_stmt_perform;