training_wheels_004.patch
text/plain
Filename: training_wheels_004.patch
Type: text/plain
Part: 0
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 | + | − |
|---|---|---|
| contrib/Makefile | 1 | 0 |
| contrib/require_where/Makefile | 17 | 0 |
| contrib/require_where/require_where.c | 92 | 0 |
| doc/src/sgml/contrib.sgml | 1 | 0 |
| doc/src/sgml/filelist.sgml | 1 | 0 |
| doc/src/sgml/require_where.sgml | 89 | 0 |
diff --git a/contrib/Makefile b/contrib/Makefile
index 25263c0..4bd456f 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -40,6 +40,7 @@ SUBDIRS = \
pgstattuple \
pg_visibility \
postgres_fdw \
+ require_where \
seg \
spi \
tablefunc \
diff --git a/contrib/require_where/Makefile b/contrib/require_where/Makefile
new file mode 100644
index 0000000..0cf3663
--- /dev/null
+++ b/contrib/require_where/Makefile
@@ -0,0 +1,17 @@
+# contrib/require_where/Makefile
+
+MODULE_big = require_where
+OBJS = require_where.o
+
+PGFILEDESC = 'require_where - require DELETE and/or UPDATE to have a WHERE clause'
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS = $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/require_where
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_builddir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/require_where/require_where.c b/contrib/require_where/require_where.c
new file mode 100644
index 0000000..181b3bb
--- /dev/null
+++ b/contrib/require_where/require_where.c
@@ -0,0 +1,92 @@
+/*
+ * --------------------------------------------------------------------------
+ *
+ * require_where.c
+ *
+ * Copyright (C) 2016, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * contrib/require_where/require_where.c
+ *
+ * --------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+
+#include "parser/analyze.h"
+
+#include "utils/elog.h"
+#include "utils/guc.h"
+
+PG_MODULE_MAGIC;
+
+void _PG_init(void);
+void _PG_fini(void);
+
+static post_parse_analyze_hook_type original_post_parse_analyze_hook = NULL;
+static bool require_where_delete = false;
+static bool require_where_update = false;
+
+static void
+require_where_check(ParseState *pstate, Query *query)
+{
+
+ if (require_where_delete && query->commandType == CMD_DELETE)
+ {
+ Assert(query->jointree != NULL);
+ if (query->jointree->quals == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("DELETE requires a WHERE clause"),
+ errhint("To delete all rows, use \"WHERE true\" or similar.")));
+ }
+
+ if (require_where_update && query->commandType == CMD_UPDATE)
+ {
+ Assert(query->jointree != NULL);
+ if (query->jointree->quals == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("UPDATE requires a WHERE clause"),
+ errhint("To update all rows, use \"WHERE true\" or similar.")));
+ }
+
+ if (original_post_parse_analyze_hook != NULL)
+ (*original_post_parse_analyze_hook) (pstate, query);
+}
+
+void
+_PG_init(void)
+{
+ DefineCustomBoolVariable("require_where.delete",
+ "Require every DELETE statement to have a WHERE clause.",
+ NULL,
+ &require_where_delete,
+ false,
+ PGC_SUSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+
+ DefineCustomBoolVariable("require_where.update",
+ "Require every UPDATE statement to have a WHERE clause.",
+ NULL,
+ &require_where_update,
+ false,
+ PGC_SUSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+
+ original_post_parse_analyze_hook = post_parse_analyze_hook;
+ post_parse_analyze_hook = require_where_check;
+}
+
+void
+_PG_fini(void)
+{
+ post_parse_analyze_hook = original_post_parse_analyze_hook;
+}
diff --git a/doc/src/sgml/contrib.sgml b/doc/src/sgml/contrib.sgml
index c8708ec..7ca62a4 100644
--- a/doc/src/sgml/contrib.sgml
+++ b/doc/src/sgml/contrib.sgml
@@ -135,6 +135,7 @@ CREATE EXTENSION <replaceable>module_name</> FROM unpackaged;
&pgtrgm;
&pgvisibility;
&postgres-fdw;
+ &require_where;
&seg;
&sepgsql;
&contrib-spi;
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 4383711..54b6bdc 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -140,6 +140,7 @@
<!ENTITY pgtrgm SYSTEM "pgtrgm.sgml">
<!ENTITY pgvisibility SYSTEM "pgvisibility.sgml">
<!ENTITY postgres-fdw SYSTEM "postgres-fdw.sgml">
+<!ENTITY require_where SYSTEM "require_where.sgml">
<!ENTITY seg SYSTEM "seg.sgml">
<!ENTITY contrib-spi SYSTEM "contrib-spi.sgml">
<!ENTITY sepgsql SYSTEM "sepgsql.sgml">
diff --git a/doc/src/sgml/require_where.sgml b/doc/src/sgml/require_where.sgml
new file mode 100644
index 0000000..0b2e290
--- /dev/null
+++ b/doc/src/sgml/require_where.sgml
@@ -0,0 +1,89 @@
+<!-- doc/src/sgml/require_where.sgml -->
+
+<sect1 id="require_where" xreflabel="require_where">
+ <title>require_where</title>
+
+ <indexterm zone="require_where">
+ <primary>require_where</primary>
+ </indexterm>
+
+ <para>
+ This module allows a superuser to require that WHERE clauses on
+ either DELETE or UPDATE not be empty using a custom GUC to control
+ each.
+ </para>
+
+ <para>
+ To use this module, you must include <literal>require_where</literal>
+ in the <xref linkend="guc-shared-preload-libraries"> parameter.
+ </para>
+
+ <para>
+ Here is an example showing how to set up a database cluster with
+ <literal>require_where</literal>.
+<screen>
+$ psql -U postgres
+# SHOW shared_preload_libraries; /* Make sure not to clobber something by accident */
+
+If you found something,
+# ALTER SYSTEM SET shared_preload_libraries='the,stuff,you,found,require_where';
+
+Otherwise,
+# ALTER SYSTEM SET shared_preload_libraries='require_where';
+
+Then restart <productname>PostgreSQL</productname>
+</screen>
+ </para>
+
+
+ <sect2>
+ <title>GUC Parameters</title>
+
+ <variablelist>
+ <varlistentry id="guc-require_where-delete" xreflabel="require_where.delete">
+ <term>
+ <varname>require_where.delete</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>require_where.delete</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ This parameter defaults to <literal>false</literal>. When set
+ to <literal>true</literal>, every <literal>DELETE</literal> requires
+ some kind of <literal>WHERE</literal> clause in order to
+ execute. When <literal>DELETE</literal> is meant to span the
+ entire relation, one can issue a <literal>WHERE true</literal>
+ or equivalent.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="guc-require_where-update" xreflabel="require_where.update">
+ <term>
+ <varname>require_where.update</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>require_where.update</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ This parameter defaults to <literal>false</literal>. When set
+ to <literal>true</literal>, every <literal>UPDATE</literal> requires
+ some kind of <literal>WHERE</literal> clause in order to
+ execute. When <literal>UPDATE</literal> is meant to span the
+ entire relation, one can issue a <literal>WHERE true</literal>
+ or equivalent.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2>
+ <title>Authors</title>
+
+ <para>
+ David Fetter <email>david@fetter.org</email>, Oakland, California, USA
+ </para>
+ </sect2>
+</sect1>