training_wheels_001.patch

text/plain

Filename: training_wheels_001.patch
Type: text/plain
Part: 0
Message: PoC: Make it possible to disallow WHERE-less UPDATE and DELETE

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: unified
File+
doc/src/sgml/config.sgml 26 0
src/backend/parser/analyze.c 15 0
src/backend/utils/errcodes.txt 1 0
src/backend/utils/misc/guc.c 21 0
src/include/parser/analyze.h 3 0
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index c9e0ec2..c01db8d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7019,6 +7019,32 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-allow-empty-updates" xreflabel="allow_empty_updates">
+      <term><varname>allow_empty_updates</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>allow_empty_updates</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Allow UPDATE statements that lack a WHERE clause.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-allow-empty-deletes" xreflabel="allow_empty_deletes">
+      <term><varname>allow_empty_deletes</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>allow_empty_deletes</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Allow DELETE statements that lack a WHERE clause.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
    </sect1>
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 29c8c4e..0c8786e 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -48,6 +48,9 @@
 /* Hook for plugins to get control at end of parse analysis */
 post_parse_analyze_hook_type post_parse_analyze_hook = NULL;
 
+bool allow_empty_deletes = true;
+bool allow_empty_updates = true;
+
 static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
 static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
 static List *transformInsertRow(ParseState *pstate, List *exprlist,
@@ -408,6 +411,12 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
 	qual = transformWhereClause(pstate, stmt->whereClause,
 								EXPR_KIND_WHERE, "WHERE");
 
+	/* Check for allow_empty_deletes */
+	if (!allow_empty_deletes && qual == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_STATEMENT_HAS_NO_WHERE),
+				 errmsg("DELETE without a WHERE clause is disallowed")));
+
 	qry->returningList = transformReturningList(pstate, stmt->returningList);
 
 	/* done building the range table and jointree */
@@ -2110,6 +2119,12 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 	qual = transformWhereClause(pstate, stmt->whereClause,
 								EXPR_KIND_WHERE, "WHERE");
 
+	/* Check for allow_empty_updates */
+	if (!allow_empty_updates && qual == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_STATEMENT_HAS_NO_WHERE),
+				 errmsg("UPDATE without a WHERE clause is disallowed")));
+
 	qry->returningList = transformReturningList(pstate, stmt->returningList);
 
 	/*
diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt
index be924d5..254cf10 100644
--- a/src/backend/utils/errcodes.txt
+++ b/src/backend/utils/errcodes.txt
@@ -388,6 +388,7 @@ Section: Class 54 - Program Limit Exceeded
 # this is for wired-in limits, not resource exhaustion problems (class borrowed from DB2)
 54000    E    ERRCODE_PROGRAM_LIMIT_EXCEEDED                                 program_limit_exceeded
 54001    E    ERRCODE_STATEMENT_TOO_COMPLEX                                  statement_too_complex
+54002    E    ERRCODE_STATEMENT_HAS_NO_WHERE                                 statement_has_no_where
 54011    E    ERRCODE_TOO_MANY_COLUMNS                                       too_many_columns
 54023    E    ERRCODE_TOO_MANY_ARGUMENTS                                     too_many_arguments
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6ac5184..fca6b71 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -47,6 +47,7 @@
 #include "optimizer/geqo.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
+#include "parser/analyze.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_type.h"
 #include "parser/parser.h"
@@ -1653,6 +1654,26 @@ static struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"allow_empty_deletes", PGC_SUSET, QUERY_TUNING,
+			gettext_noop("Allow DELETE without a WHERE clause"),
+			NULL
+		},
+		&allow_empty_deletes,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"allow_empty_updates", PGC_SUSET, QUERY_TUNING,
+			gettext_noop("Allow UPDATE without a WHERE clause"),
+			NULL
+		},
+		&allow_empty_updates,
+		true,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h
index 5ba322a..b88f8cd 100644
--- a/src/include/parser/analyze.h
+++ b/src/include/parser/analyze.h
@@ -42,4 +42,7 @@ extern void applyLockingClause(Query *qry, Index rtindex,
 				   LockClauseStrength strength,
 				   LockWaitPolicy waitPolicy, bool pushedDown);
 
+extern bool allow_empty_deletes;
+extern bool allow_empty_updates;
+
 #endif   /* ANALYZE_H */