From 458857cc9d7d00711b272a0dabbcb591b506d6b8 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 12 Oct 2011 15:45:03 -0400
Subject: [PATCH] Throw a useful error message if an extension script file is
 fed to psql.

We have seen one too many reports of people trying to use 9.1 extension
files in the old-fashioned way of sourcing them in psql.  Not only does
that usually not work (due to failure to substitute for MODULE_PATHNAME
and/or @extschema@), but if it did work they'd get a collection of loose
objects not an extension.  To prevent this, insert an \echo ... \quit
line that prints a suitable error message into each extension script file,
and teach commands/extension.c to ignore lines starting with \echo.
That should not only prevent any adverse consequences of loading a script
file the wrong way, but make it crystal clear to users that they need to
do it differently now.

Tom Lane, following an idea of Andrew Dunstan's.  Back-patch into 9.1
... there is not going to be much value in this if we wait till 9.2.
---
 contrib/adminpack/adminpack--1.0.sql          |  3 ++
 contrib/btree_gin/btree_gin--1.0.sql          |  3 ++
 .../btree_gin/btree_gin--unpackaged--1.0.sql  |  3 ++
 contrib/btree_gist/btree_gist--1.0.sql        |  3 ++
 .../btree_gist--unpackaged--1.0.sql           |  3 ++
 contrib/chkpass/chkpass--1.0.sql              |  3 ++
 contrib/chkpass/chkpass--unpackaged--1.0.sql  |  3 ++
 contrib/citext/citext--1.0.sql                |  3 ++
 contrib/citext/citext--unpackaged--1.0.sql    |  3 ++
 contrib/cube/cube--1.0.sql                    |  3 ++
 contrib/cube/cube--unpackaged--1.0.sql        |  3 ++
 contrib/dblink/dblink--1.0.sql                |  3 ++
 contrib/dblink/dblink--unpackaged--1.0.sql    |  3 ++
 contrib/dict_int/dict_int--1.0.sql            |  3 ++
 .../dict_int/dict_int--unpackaged--1.0.sql    |  3 ++
 contrib/dict_xsyn/dict_xsyn--1.0.sql          |  3 ++
 .../dict_xsyn/dict_xsyn--unpackaged--1.0.sql  |  3 ++
 contrib/earthdistance/earthdistance--1.0.sql  |  3 ++
 .../earthdistance--unpackaged--1.0.sql        |  3 ++
 contrib/file_fdw/file_fdw--1.0.sql            |  3 ++
 contrib/fuzzystrmatch/fuzzystrmatch--1.0.sql  |  3 ++
 .../fuzzystrmatch--unpackaged--1.0.sql        |  3 ++
 contrib/hstore/hstore--1.0.sql                |  3 ++
 contrib/hstore/hstore--unpackaged--1.0.sql    |  3 ++
 contrib/intagg/intagg--1.0.sql                |  3 ++
 contrib/intagg/intagg--unpackaged--1.0.sql    |  3 ++
 contrib/intarray/intarray--1.0.sql            |  3 ++
 .../intarray/intarray--unpackaged--1.0.sql    |  3 ++
 contrib/isn/isn--1.0.sql                      |  3 ++
 contrib/isn/isn--unpackaged--1.0.sql          |  3 ++
 contrib/lo/lo--1.0.sql                        |  3 ++
 contrib/lo/lo--unpackaged--1.0.sql            |  3 ++
 contrib/ltree/ltree--1.0.sql                  |  3 ++
 contrib/ltree/ltree--unpackaged--1.0.sql      |  3 ++
 contrib/pageinspect/pageinspect--1.0.sql      |  3 ++
 .../pageinspect--unpackaged--1.0.sql          |  3 ++
 .../pg_buffercache/pg_buffercache--1.0.sql    |  3 ++
 .../pg_buffercache--unpackaged--1.0.sql       |  3 ++
 .../pg_freespacemap/pg_freespacemap--1.0.sql  |  3 ++
 .../pg_freespacemap--unpackaged--1.0.sql      |  3 ++
 .../pg_stat_statements--1.0.sql               |  3 ++
 .../pg_stat_statements--unpackaged--1.0.sql   |  3 ++
 contrib/pg_trgm/pg_trgm--1.0.sql              |  3 ++
 contrib/pg_trgm/pg_trgm--unpackaged--1.0.sql  |  3 ++
 contrib/pgcrypto/pgcrypto--1.0.sql            |  3 ++
 .../pgcrypto/pgcrypto--unpackaged--1.0.sql    |  3 ++
 contrib/pgrowlocks/pgrowlocks--1.0.sql        |  3 ++
 .../pgrowlocks--unpackaged--1.0.sql           |  3 ++
 contrib/pgstattuple/pgstattuple--1.0.sql      |  3 ++
 .../pgstattuple--unpackaged--1.0.sql          |  3 ++
 contrib/seg/seg--1.0.sql                      |  3 ++
 contrib/seg/seg--unpackaged--1.0.sql          |  3 ++
 contrib/spi/autoinc--1.0.sql                  |  3 ++
 contrib/spi/autoinc--unpackaged--1.0.sql      |  3 ++
 contrib/spi/insert_username--1.0.sql          |  3 ++
 .../spi/insert_username--unpackaged--1.0.sql  |  3 ++
 contrib/spi/moddatetime--1.0.sql              |  3 ++
 contrib/spi/moddatetime--unpackaged--1.0.sql  |  3 ++
 contrib/spi/refint--1.0.sql                   |  3 ++
 contrib/spi/refint--unpackaged--1.0.sql       |  3 ++
 contrib/spi/timetravel--1.0.sql               |  3 ++
 contrib/spi/timetravel--unpackaged--1.0.sql   |  3 ++
 contrib/sslinfo/sslinfo--1.0.sql              |  3 ++
 contrib/sslinfo/sslinfo--unpackaged--1.0.sql  |  3 ++
 contrib/tablefunc/tablefunc--1.0.sql          |  3 ++
 .../tablefunc/tablefunc--unpackaged--1.0.sql  |  3 ++
 contrib/test_parser/test_parser--1.0.sql      |  3 ++
 .../test_parser--unpackaged--1.0.sql          |  3 ++
 contrib/tsearch2/tsearch2--1.0.sql            |  3 ++
 .../tsearch2/tsearch2--unpackaged--1.0.sql    |  3 ++
 contrib/unaccent/unaccent--1.0.sql            |  3 ++
 .../unaccent/unaccent--unpackaged--1.0.sql    |  3 ++
 contrib/uuid-ossp/uuid-ossp--1.0.sql          |  3 ++
 .../uuid-ossp/uuid-ossp--unpackaged--1.0.sql  |  3 ++
 contrib/xml2/xml2--1.0.sql                    |  3 ++
 contrib/xml2/xml2--unpackaged--1.0.sql        |  3 ++
 doc/src/sgml/extend.sgml                      | 14 ++++++
 src/backend/commands/extension.c              | 49 ++++++++++++-------
 78 files changed, 274 insertions(+), 17 deletions(-)

diff --git a/contrib/adminpack/adminpack--1.0.sql b/contrib/adminpack/adminpack--1.0.sql
index 090702231c0..f76f5c3cdf7 100644
--- a/contrib/adminpack/adminpack--1.0.sql
+++ b/contrib/adminpack/adminpack--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/adminpack/adminpack--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION adminpack" to load this file. \quit
+
 /* ***********************************************
  * Administrative functions for PostgreSQL
  * *********************************************** */
diff --git a/contrib/btree_gin/btree_gin--1.0.sql b/contrib/btree_gin/btree_gin--1.0.sql
index 07f93640f33..cf867ef6873 100644
--- a/contrib/btree_gin/btree_gin--1.0.sql
+++ b/contrib/btree_gin/btree_gin--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/btree_gin/btree_gin--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION btree_gin" to load this file. \quit
+
 CREATE FUNCTION gin_btree_consistent(internal, int2, anyelement, int4, internal, internal)
 RETURNS bool
 AS 'MODULE_PATHNAME'
diff --git a/contrib/btree_gin/btree_gin--unpackaged--1.0.sql b/contrib/btree_gin/btree_gin--unpackaged--1.0.sql
index fe1ddeab878..8dfafc1e8b9 100644
--- a/contrib/btree_gin/btree_gin--unpackaged--1.0.sql
+++ b/contrib/btree_gin/btree_gin--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/btree_gin/btree_gin--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION btree_gin" to load this file. \quit
+
 ALTER EXTENSION btree_gin ADD function gin_btree_consistent(internal,smallint,anyelement,integer,internal,internal);
 ALTER EXTENSION btree_gin ADD function gin_extract_value_int2(smallint,internal);
 ALTER EXTENSION btree_gin ADD function gin_compare_prefix_int2(smallint,smallint,smallint,internal);
diff --git a/contrib/btree_gist/btree_gist--1.0.sql b/contrib/btree_gist/btree_gist--1.0.sql
index dd428995c18..c5c958753e3 100644
--- a/contrib/btree_gist/btree_gist--1.0.sql
+++ b/contrib/btree_gist/btree_gist--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/btree_gist/btree_gist--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION btree_gist" to load this file. \quit
+
 CREATE FUNCTION gbtreekey4_in(cstring)
 RETURNS gbtreekey4
 AS 'MODULE_PATHNAME', 'gbtreekey_in'
diff --git a/contrib/btree_gist/btree_gist--unpackaged--1.0.sql b/contrib/btree_gist/btree_gist--unpackaged--1.0.sql
index 00252bf7c38..838ad7ec1e1 100644
--- a/contrib/btree_gist/btree_gist--unpackaged--1.0.sql
+++ b/contrib/btree_gist/btree_gist--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/btree_gist/btree_gist--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION btree_gist" to load this file. \quit
+
 ALTER EXTENSION btree_gist ADD type gbtreekey4;
 ALTER EXTENSION btree_gist ADD function gbtreekey4_in(cstring);
 ALTER EXTENSION btree_gist ADD function gbtreekey4_out(gbtreekey4);
diff --git a/contrib/chkpass/chkpass--1.0.sql b/contrib/chkpass/chkpass--1.0.sql
index 755fee3bc3f..d1fbedc4468 100644
--- a/contrib/chkpass/chkpass--1.0.sql
+++ b/contrib/chkpass/chkpass--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/chkpass/chkpass--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION chkpass" to load this file. \quit
+
 --
 --	Input and output functions and the type itself:
 --
diff --git a/contrib/chkpass/chkpass--unpackaged--1.0.sql b/contrib/chkpass/chkpass--unpackaged--1.0.sql
index bf91950f3c6..7bbfb142a6a 100644
--- a/contrib/chkpass/chkpass--unpackaged--1.0.sql
+++ b/contrib/chkpass/chkpass--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/chkpass/chkpass--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION chkpass" to load this file. \quit
+
 ALTER EXTENSION chkpass ADD type chkpass;
 ALTER EXTENSION chkpass ADD function chkpass_in(cstring);
 ALTER EXTENSION chkpass ADD function chkpass_out(chkpass);
diff --git a/contrib/citext/citext--1.0.sql b/contrib/citext/citext--1.0.sql
index 2760f7e08d9..1dd19973d77 100644
--- a/contrib/citext/citext--1.0.sql
+++ b/contrib/citext/citext--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/citext/citext--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION citext" to load this file. \quit
+
 --
 --  PostgreSQL code for CITEXT.
 --
diff --git a/contrib/citext/citext--unpackaged--1.0.sql b/contrib/citext/citext--unpackaged--1.0.sql
index a59df36797c..42d7aeeb7ff 100644
--- a/contrib/citext/citext--unpackaged--1.0.sql
+++ b/contrib/citext/citext--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/citext/citext--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION citext" to load this file. \quit
+
 ALTER EXTENSION citext ADD type citext;
 ALTER EXTENSION citext ADD function citextin(cstring);
 ALTER EXTENSION citext ADD function citextout(citext);
diff --git a/contrib/cube/cube--1.0.sql b/contrib/cube/cube--1.0.sql
index ee9febe0053..0307811ceb9 100644
--- a/contrib/cube/cube--1.0.sql
+++ b/contrib/cube/cube--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/cube/cube--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION cube" to load this file. \quit
+
 -- Create the user-defined type for N-dimensional boxes
 
 CREATE FUNCTION cube_in(cstring)
diff --git a/contrib/cube/cube--unpackaged--1.0.sql b/contrib/cube/cube--unpackaged--1.0.sql
index 866c18a2898..68596827861 100644
--- a/contrib/cube/cube--unpackaged--1.0.sql
+++ b/contrib/cube/cube--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/cube/cube--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION cube" to load this file. \quit
+
 ALTER EXTENSION cube ADD type cube;
 ALTER EXTENSION cube ADD function cube_in(cstring);
 ALTER EXTENSION cube ADD function cube(double precision[],double precision[]);
diff --git a/contrib/dblink/dblink--1.0.sql b/contrib/dblink/dblink--1.0.sql
index 4ac55144619..1fec9e39441 100644
--- a/contrib/dblink/dblink--1.0.sql
+++ b/contrib/dblink/dblink--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/dblink/dblink--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION dblink" to load this file. \quit
+
 -- dblink_connect now restricts non-superusers to password
 -- authenticated connections
 CREATE FUNCTION dblink_connect (text)
diff --git a/contrib/dblink/dblink--unpackaged--1.0.sql b/contrib/dblink/dblink--unpackaged--1.0.sql
index b6d184b4a2c..29f5bed0c13 100644
--- a/contrib/dblink/dblink--unpackaged--1.0.sql
+++ b/contrib/dblink/dblink--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/dblink/dblink--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION dblink" to load this file. \quit
+
 ALTER EXTENSION dblink ADD function dblink_connect(text);
 ALTER EXTENSION dblink ADD function dblink_connect(text,text);
 ALTER EXTENSION dblink ADD function dblink_connect_u(text);
diff --git a/contrib/dict_int/dict_int--1.0.sql b/contrib/dict_int/dict_int--1.0.sql
index 585a56552d6..acb1461b569 100644
--- a/contrib/dict_int/dict_int--1.0.sql
+++ b/contrib/dict_int/dict_int--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/dict_int/dict_int--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION dict_int" to load this file. \quit
+
 CREATE FUNCTION dintdict_init(internal)
         RETURNS internal
         AS 'MODULE_PATHNAME'
diff --git a/contrib/dict_int/dict_int--unpackaged--1.0.sql b/contrib/dict_int/dict_int--unpackaged--1.0.sql
index f89218a565c..ef59b046ee6 100644
--- a/contrib/dict_int/dict_int--unpackaged--1.0.sql
+++ b/contrib/dict_int/dict_int--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/dict_int/dict_int--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION dict_int" to load this file. \quit
+
 ALTER EXTENSION dict_int ADD function dintdict_init(internal);
 ALTER EXTENSION dict_int ADD function dintdict_lexize(internal,internal,internal,internal);
 ALTER EXTENSION dict_int ADD text search template intdict_template;
diff --git a/contrib/dict_xsyn/dict_xsyn--1.0.sql b/contrib/dict_xsyn/dict_xsyn--1.0.sql
index 30eaff4db5a..3d6bb51ca89 100644
--- a/contrib/dict_xsyn/dict_xsyn--1.0.sql
+++ b/contrib/dict_xsyn/dict_xsyn--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/dict_xsyn/dict_xsyn--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION dict_xsyn" to load this file. \quit
+
 CREATE FUNCTION dxsyn_init(internal)
         RETURNS internal
         AS 'MODULE_PATHNAME'
diff --git a/contrib/dict_xsyn/dict_xsyn--unpackaged--1.0.sql b/contrib/dict_xsyn/dict_xsyn--unpackaged--1.0.sql
index 6fe0285f799..1d193f7981a 100644
--- a/contrib/dict_xsyn/dict_xsyn--unpackaged--1.0.sql
+++ b/contrib/dict_xsyn/dict_xsyn--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/dict_xsyn/dict_xsyn--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION dict_xsyn" to load this file. \quit
+
 ALTER EXTENSION dict_xsyn ADD function dxsyn_init(internal);
 ALTER EXTENSION dict_xsyn ADD function dxsyn_lexize(internal,internal,internal,internal);
 ALTER EXTENSION dict_xsyn ADD text search template xsyn_template;
diff --git a/contrib/earthdistance/earthdistance--1.0.sql b/contrib/earthdistance/earthdistance--1.0.sql
index 71e4025f6f8..4af9062e7d8 100644
--- a/contrib/earthdistance/earthdistance--1.0.sql
+++ b/contrib/earthdistance/earthdistance--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/earthdistance/earthdistance--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION earthdistance" to load this file. \quit
+
 -- earth() returns the radius of the earth in meters. This is the only
 -- place you need to change things for the cube base distance functions
 -- in order to use different units (or a better value for the Earth's radius).
diff --git a/contrib/earthdistance/earthdistance--unpackaged--1.0.sql b/contrib/earthdistance/earthdistance--unpackaged--1.0.sql
index 2d5919cc72d..362e0ac1071 100644
--- a/contrib/earthdistance/earthdistance--unpackaged--1.0.sql
+++ b/contrib/earthdistance/earthdistance--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/earthdistance/earthdistance--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION earthdistance" to load this file. \quit
+
 ALTER EXTENSION earthdistance ADD function earth();
 ALTER EXTENSION earthdistance ADD type earth;
 ALTER EXTENSION earthdistance ADD function sec_to_gc(double precision);
diff --git a/contrib/file_fdw/file_fdw--1.0.sql b/contrib/file_fdw/file_fdw--1.0.sql
index 0cca65f4638..856e6bf0a71 100644
--- a/contrib/file_fdw/file_fdw--1.0.sql
+++ b/contrib/file_fdw/file_fdw--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/file_fdw/file_fdw--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION file_fdw" to load this file. \quit
+
 CREATE FUNCTION file_fdw_handler()
 RETURNS fdw_handler
 AS 'MODULE_PATHNAME'
diff --git a/contrib/fuzzystrmatch/fuzzystrmatch--1.0.sql b/contrib/fuzzystrmatch/fuzzystrmatch--1.0.sql
index d9b8987adf5..1cf9b6188cc 100644
--- a/contrib/fuzzystrmatch/fuzzystrmatch--1.0.sql
+++ b/contrib/fuzzystrmatch/fuzzystrmatch--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/fuzzystrmatch/fuzzystrmatch--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION fuzzystrmatch" to load this file. \quit
+
 CREATE FUNCTION levenshtein (text,text) RETURNS int
 AS 'MODULE_PATHNAME','levenshtein'
 LANGUAGE C IMMUTABLE STRICT;
diff --git a/contrib/fuzzystrmatch/fuzzystrmatch--unpackaged--1.0.sql b/contrib/fuzzystrmatch/fuzzystrmatch--unpackaged--1.0.sql
index b99510bcddc..b9a805a4fe5 100644
--- a/contrib/fuzzystrmatch/fuzzystrmatch--unpackaged--1.0.sql
+++ b/contrib/fuzzystrmatch/fuzzystrmatch--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/fuzzystrmatch/fuzzystrmatch--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION fuzzystrmatch" to load this file. \quit
+
 ALTER EXTENSION fuzzystrmatch ADD function levenshtein(text,text);
 ALTER EXTENSION fuzzystrmatch ADD function levenshtein(text,text,integer,integer,integer);
 ALTER EXTENSION fuzzystrmatch ADD function metaphone(text,integer);
diff --git a/contrib/hstore/hstore--1.0.sql b/contrib/hstore/hstore--1.0.sql
index 247a2773f5a..8b211c4669f 100644
--- a/contrib/hstore/hstore--1.0.sql
+++ b/contrib/hstore/hstore--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/hstore/hstore--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION hstore" to load this file. \quit
+
 CREATE TYPE hstore;
 
 CREATE FUNCTION hstore_in(cstring)
diff --git a/contrib/hstore/hstore--unpackaged--1.0.sql b/contrib/hstore/hstore--unpackaged--1.0.sql
index 0eb300ecf51..b7e73f41232 100644
--- a/contrib/hstore/hstore--unpackaged--1.0.sql
+++ b/contrib/hstore/hstore--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/hstore/hstore--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION hstore" to load this file. \quit
+
 ALTER EXTENSION hstore ADD type hstore;
 ALTER EXTENSION hstore ADD function hstore_in(cstring);
 ALTER EXTENSION hstore ADD function hstore_out(hstore);
diff --git a/contrib/intagg/intagg--1.0.sql b/contrib/intagg/intagg--1.0.sql
index 19a57c079b8..f96b6e2e9b7 100644
--- a/contrib/intagg/intagg--1.0.sql
+++ b/contrib/intagg/intagg--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/intagg/intagg--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION intagg" to load this file. \quit
+
 -- Internal function for the aggregate
 -- Is called for each item in an aggregation
 CREATE FUNCTION int_agg_state (internal, int4)
diff --git a/contrib/intagg/intagg--unpackaged--1.0.sql b/contrib/intagg/intagg--unpackaged--1.0.sql
index 95238d9c675..6a6663d092c 100644
--- a/contrib/intagg/intagg--unpackaged--1.0.sql
+++ b/contrib/intagg/intagg--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/intagg/intagg--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION intagg" to load this file. \quit
+
 ALTER EXTENSION intagg ADD function int_agg_state(internal,integer);
 ALTER EXTENSION intagg ADD function int_agg_final_array(internal);
 ALTER EXTENSION intagg ADD function int_array_aggregate(integer);
diff --git a/contrib/intarray/intarray--1.0.sql b/contrib/intarray/intarray--1.0.sql
index 3b77c516cbc..0b89e0f55e5 100644
--- a/contrib/intarray/intarray--1.0.sql
+++ b/contrib/intarray/intarray--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/intarray/intarray--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION intarray" to load this file. \quit
+
 --
 -- Create the user-defined type for the 1-D integer arrays (_int4)
 --
diff --git a/contrib/intarray/intarray--unpackaged--1.0.sql b/contrib/intarray/intarray--unpackaged--1.0.sql
index 5a2829c9f53..5de64bf0aba 100644
--- a/contrib/intarray/intarray--unpackaged--1.0.sql
+++ b/contrib/intarray/intarray--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/intarray/intarray--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION intarray" to load this file. \quit
+
 ALTER EXTENSION intarray ADD type query_int;
 ALTER EXTENSION intarray ADD function bqarr_in(cstring);
 ALTER EXTENSION intarray ADD function bqarr_out(query_int);
diff --git a/contrib/isn/isn--1.0.sql b/contrib/isn/isn--1.0.sql
index 336ad1db3ce..0df7bba3b32 100644
--- a/contrib/isn/isn--1.0.sql
+++ b/contrib/isn/isn--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/isn/isn--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION isn" to load this file. \quit
+
 -- Example:
 --   create table test ( id isbn );
 --   insert into test values('978-0-393-04002-9');
diff --git a/contrib/isn/isn--unpackaged--1.0.sql b/contrib/isn/isn--unpackaged--1.0.sql
index 6130a43e515..30e50121566 100644
--- a/contrib/isn/isn--unpackaged--1.0.sql
+++ b/contrib/isn/isn--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/isn/isn--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION isn" to load this file. \quit
+
 ALTER EXTENSION isn ADD type ean13;
 ALTER EXTENSION isn ADD function ean13_in(cstring);
 ALTER EXTENSION isn ADD function ean13_out(ean13);
diff --git a/contrib/lo/lo--1.0.sql b/contrib/lo/lo--1.0.sql
index 4b9a7dee32e..cb350e0b8a0 100644
--- a/contrib/lo/lo--1.0.sql
+++ b/contrib/lo/lo--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/lo/lo--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION lo" to load this file. \quit
+
 --
 --	Create the data type ... now just a domain over OID
 --
diff --git a/contrib/lo/lo--unpackaged--1.0.sql b/contrib/lo/lo--unpackaged--1.0.sql
index 54de61686ea..053185ba1d8 100644
--- a/contrib/lo/lo--unpackaged--1.0.sql
+++ b/contrib/lo/lo--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/lo/lo--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION lo" to load this file. \quit
+
 ALTER EXTENSION lo ADD domain lo;
 ALTER EXTENSION lo ADD function lo_oid(lo);
 ALTER EXTENSION lo ADD function lo_manage();
diff --git a/contrib/ltree/ltree--1.0.sql b/contrib/ltree/ltree--1.0.sql
index 32969538a02..5a2f375a4f3 100644
--- a/contrib/ltree/ltree--1.0.sql
+++ b/contrib/ltree/ltree--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/ltree/ltree--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION ltree" to load this file. \quit
+
 CREATE FUNCTION ltree_in(cstring)
 RETURNS ltree
 AS 'MODULE_PATHNAME'
diff --git a/contrib/ltree/ltree--unpackaged--1.0.sql b/contrib/ltree/ltree--unpackaged--1.0.sql
index f483725b4af..1e24fa56c68 100644
--- a/contrib/ltree/ltree--unpackaged--1.0.sql
+++ b/contrib/ltree/ltree--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/ltree/ltree--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION ltree" to load this file. \quit
+
 ALTER EXTENSION ltree ADD type ltree;
 ALTER EXTENSION ltree ADD function ltree_in(cstring);
 ALTER EXTENSION ltree ADD function ltree_out(ltree);
diff --git a/contrib/pageinspect/pageinspect--1.0.sql b/contrib/pageinspect/pageinspect--1.0.sql
index a711f581e26..5613956fd8c 100644
--- a/contrib/pageinspect/pageinspect--1.0.sql
+++ b/contrib/pageinspect/pageinspect--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pageinspect/pageinspect--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pageinspect" to load this file. \quit
+
 --
 -- get_raw_page()
 --
diff --git a/contrib/pageinspect/pageinspect--unpackaged--1.0.sql b/contrib/pageinspect/pageinspect--unpackaged--1.0.sql
index 7d4feaf034a..13e2167dfc1 100644
--- a/contrib/pageinspect/pageinspect--unpackaged--1.0.sql
+++ b/contrib/pageinspect/pageinspect--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pageinspect/pageinspect--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pageinspect" to load this file. \quit
+
 DROP FUNCTION heap_page_items(bytea);
 CREATE FUNCTION heap_page_items(IN page bytea,
 	OUT lp smallint,
diff --git a/contrib/pg_buffercache/pg_buffercache--1.0.sql b/contrib/pg_buffercache/pg_buffercache--1.0.sql
index 9407d214108..4ca4c44256c 100644
--- a/contrib/pg_buffercache/pg_buffercache--1.0.sql
+++ b/contrib/pg_buffercache/pg_buffercache--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pg_buffercache/pg_buffercache--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_buffercache" to load this file. \quit
+
 -- Register the function.
 CREATE FUNCTION pg_buffercache_pages()
 RETURNS SETOF RECORD
diff --git a/contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql b/contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql
index f00a954d86e..bfe6e52f8f4 100644
--- a/contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql
+++ b/contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql
@@ -1,4 +1,7 @@
 /* contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_buffercache" to load this file. \quit
+
 ALTER EXTENSION pg_buffercache ADD function pg_buffercache_pages();
 ALTER EXTENSION pg_buffercache ADD view pg_buffercache;
diff --git a/contrib/pg_freespacemap/pg_freespacemap--1.0.sql b/contrib/pg_freespacemap/pg_freespacemap--1.0.sql
index d63420e33a4..2adb52a3753 100644
--- a/contrib/pg_freespacemap/pg_freespacemap--1.0.sql
+++ b/contrib/pg_freespacemap/pg_freespacemap--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pg_freespacemap/pg_freespacemap--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_freespacemap" to load this file. \quit
+
 -- Register the C function.
 CREATE FUNCTION pg_freespace(regclass, bigint)
 RETURNS int2
diff --git a/contrib/pg_freespacemap/pg_freespacemap--unpackaged--1.0.sql b/contrib/pg_freespacemap/pg_freespacemap--unpackaged--1.0.sql
index 4c7487fa4e7..5e8d7e472ee 100644
--- a/contrib/pg_freespacemap/pg_freespacemap--unpackaged--1.0.sql
+++ b/contrib/pg_freespacemap/pg_freespacemap--unpackaged--1.0.sql
@@ -1,4 +1,7 @@
 /* contrib/pg_freespacemap/pg_freespacemap--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_freespacemap" to load this file. \quit
+
 ALTER EXTENSION pg_freespacemap ADD function pg_freespace(regclass,bigint);
 ALTER EXTENSION pg_freespacemap ADD function pg_freespace(regclass);
diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.0.sql b/contrib/pg_stat_statements/pg_stat_statements--1.0.sql
index e17b82c616a..5294a01dd52 100644
--- a/contrib/pg_stat_statements/pg_stat_statements--1.0.sql
+++ b/contrib/pg_stat_statements/pg_stat_statements--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pg_stat_statements/pg_stat_statements--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_stat_statements" to load this file. \quit
+
 -- Register functions.
 CREATE FUNCTION pg_stat_statements_reset()
 RETURNS void
diff --git a/contrib/pg_stat_statements/pg_stat_statements--unpackaged--1.0.sql b/contrib/pg_stat_statements/pg_stat_statements--unpackaged--1.0.sql
index 9dda85cbdfc..e84a3cbafc2 100644
--- a/contrib/pg_stat_statements/pg_stat_statements--unpackaged--1.0.sql
+++ b/contrib/pg_stat_statements/pg_stat_statements--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pg_stat_statements/pg_stat_statements--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_stat_statements" to load this file. \quit
+
 ALTER EXTENSION pg_stat_statements ADD function pg_stat_statements_reset();
 ALTER EXTENSION pg_stat_statements ADD function pg_stat_statements();
 ALTER EXTENSION pg_stat_statements ADD view pg_stat_statements;
diff --git a/contrib/pg_trgm/pg_trgm--1.0.sql b/contrib/pg_trgm/pg_trgm--1.0.sql
index d9cdd23d85f..8067bd60339 100644
--- a/contrib/pg_trgm/pg_trgm--1.0.sql
+++ b/contrib/pg_trgm/pg_trgm--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pg_trgm/pg_trgm--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_trgm" to load this file. \quit
+
 CREATE FUNCTION set_limit(float4)
 RETURNS float4
 AS 'MODULE_PATHNAME'
diff --git a/contrib/pg_trgm/pg_trgm--unpackaged--1.0.sql b/contrib/pg_trgm/pg_trgm--unpackaged--1.0.sql
index 0e1c63f0752..7243a6a410f 100644
--- a/contrib/pg_trgm/pg_trgm--unpackaged--1.0.sql
+++ b/contrib/pg_trgm/pg_trgm--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pg_trgm/pg_trgm--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_trgm" to load this file. \quit
+
 ALTER EXTENSION pg_trgm ADD function set_limit(real);
 ALTER EXTENSION pg_trgm ADD function show_limit();
 ALTER EXTENSION pg_trgm ADD function show_trgm(text);
diff --git a/contrib/pgcrypto/pgcrypto--1.0.sql b/contrib/pgcrypto/pgcrypto--1.0.sql
index 52be0950ce6..d95a51bc406 100644
--- a/contrib/pgcrypto/pgcrypto--1.0.sql
+++ b/contrib/pgcrypto/pgcrypto--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pgcrypto/pgcrypto--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
 CREATE FUNCTION digest(text, text)
 RETURNS bytea
 AS 'MODULE_PATHNAME', 'pg_digest'
diff --git a/contrib/pgcrypto/pgcrypto--unpackaged--1.0.sql b/contrib/pgcrypto/pgcrypto--unpackaged--1.0.sql
index 64f0cdf23ac..fe8d4c4e72c 100644
--- a/contrib/pgcrypto/pgcrypto--unpackaged--1.0.sql
+++ b/contrib/pgcrypto/pgcrypto--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pgcrypto/pgcrypto--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
 ALTER EXTENSION pgcrypto ADD function digest(text,text);
 ALTER EXTENSION pgcrypto ADD function digest(bytea,text);
 ALTER EXTENSION pgcrypto ADD function hmac(text,text,text);
diff --git a/contrib/pgrowlocks/pgrowlocks--1.0.sql b/contrib/pgrowlocks/pgrowlocks--1.0.sql
index 0b60fdcd07f..a909b7430d8 100644
--- a/contrib/pgrowlocks/pgrowlocks--1.0.sql
+++ b/contrib/pgrowlocks/pgrowlocks--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pgrowlocks/pgrowlocks--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pgrowlocks" to load this file. \quit
+
 CREATE FUNCTION pgrowlocks(IN relname text,
     OUT locked_row TID,		-- row TID
     OUT lock_type TEXT,		-- lock type
diff --git a/contrib/pgrowlocks/pgrowlocks--unpackaged--1.0.sql b/contrib/pgrowlocks/pgrowlocks--unpackaged--1.0.sql
index 2d9d1eed41a..b8c3faf1c76 100644
--- a/contrib/pgrowlocks/pgrowlocks--unpackaged--1.0.sql
+++ b/contrib/pgrowlocks/pgrowlocks--unpackaged--1.0.sql
@@ -1,3 +1,6 @@
 /* contrib/pgrowlocks/pgrowlocks--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pgrowlocks" to load this file. \quit
+
 ALTER EXTENSION pgrowlocks ADD function pgrowlocks(text);
diff --git a/contrib/pgstattuple/pgstattuple--1.0.sql b/contrib/pgstattuple/pgstattuple--1.0.sql
index 83445ec4aee..f7e03083ad7 100644
--- a/contrib/pgstattuple/pgstattuple--1.0.sql
+++ b/contrib/pgstattuple/pgstattuple--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pgstattuple/pgstattuple--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit
+
 CREATE FUNCTION pgstattuple(IN relname text,
     OUT table_len BIGINT,		-- physical table length in bytes
     OUT tuple_count BIGINT,		-- number of live tuples
diff --git a/contrib/pgstattuple/pgstattuple--unpackaged--1.0.sql b/contrib/pgstattuple/pgstattuple--unpackaged--1.0.sql
index 3cfb8db5347..14b63cafcf5 100644
--- a/contrib/pgstattuple/pgstattuple--unpackaged--1.0.sql
+++ b/contrib/pgstattuple/pgstattuple--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/pgstattuple/pgstattuple--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit
+
 ALTER EXTENSION pgstattuple ADD function pgstattuple(text);
 ALTER EXTENSION pgstattuple ADD function pgstattuple(oid);
 ALTER EXTENSION pgstattuple ADD function pgstatindex(text);
diff --git a/contrib/seg/seg--1.0.sql b/contrib/seg/seg--1.0.sql
index 563411da6a0..3230b94f409 100644
--- a/contrib/seg/seg--1.0.sql
+++ b/contrib/seg/seg--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/seg/seg--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION seg" to load this file. \quit
+
 -- Create the user-defined type for 1-D floating point intervals (seg)
 
 CREATE FUNCTION seg_in(cstring)
diff --git a/contrib/seg/seg--unpackaged--1.0.sql b/contrib/seg/seg--unpackaged--1.0.sql
index 9fefbfc9aa4..ebd6b3bc5b5 100644
--- a/contrib/seg/seg--unpackaged--1.0.sql
+++ b/contrib/seg/seg--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/seg/seg--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION seg" to load this file. \quit
+
 ALTER EXTENSION seg ADD type seg;
 ALTER EXTENSION seg ADD function seg_in(cstring);
 ALTER EXTENSION seg ADD function seg_out(seg);
diff --git a/contrib/spi/autoinc--1.0.sql b/contrib/spi/autoinc--1.0.sql
index 9c9df9ce0bd..22721e003de 100644
--- a/contrib/spi/autoinc--1.0.sql
+++ b/contrib/spi/autoinc--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/spi/autoinc--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION autoinc" to load this file. \quit
+
 CREATE FUNCTION autoinc()
 RETURNS trigger
 AS 'MODULE_PATHNAME'
diff --git a/contrib/spi/autoinc--unpackaged--1.0.sql b/contrib/spi/autoinc--unpackaged--1.0.sql
index 232e9170fc6..cfe2065d3d8 100644
--- a/contrib/spi/autoinc--unpackaged--1.0.sql
+++ b/contrib/spi/autoinc--unpackaged--1.0.sql
@@ -1,3 +1,6 @@
 /* contrib/spi/autoinc--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION autoinc" to load this file. \quit
+
 ALTER EXTENSION autoinc ADD function autoinc();
diff --git a/contrib/spi/insert_username--1.0.sql b/contrib/spi/insert_username--1.0.sql
index bd854587e03..0deb0bf3f8b 100644
--- a/contrib/spi/insert_username--1.0.sql
+++ b/contrib/spi/insert_username--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/spi/insert_username--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION insert_username" to load this file. \quit
+
 CREATE FUNCTION insert_username()
 RETURNS trigger
 AS 'MODULE_PATHNAME'
diff --git a/contrib/spi/insert_username--unpackaged--1.0.sql b/contrib/spi/insert_username--unpackaged--1.0.sql
index f53cb690f12..91a5d1f3095 100644
--- a/contrib/spi/insert_username--unpackaged--1.0.sql
+++ b/contrib/spi/insert_username--unpackaged--1.0.sql
@@ -1,3 +1,6 @@
 /* contrib/spi/insert_username--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION insert_username" to load this file. \quit
+
 ALTER EXTENSION insert_username ADD function insert_username();
diff --git a/contrib/spi/moddatetime--1.0.sql b/contrib/spi/moddatetime--1.0.sql
index 97cc63289fe..2ee61b814f3 100644
--- a/contrib/spi/moddatetime--1.0.sql
+++ b/contrib/spi/moddatetime--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/spi/moddatetime--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION moddatetime" to load this file. \quit
+
 CREATE FUNCTION moddatetime()
 RETURNS trigger
 AS 'MODULE_PATHNAME'
diff --git a/contrib/spi/moddatetime--unpackaged--1.0.sql b/contrib/spi/moddatetime--unpackaged--1.0.sql
index f3a0a968371..caa49ce0dc9 100644
--- a/contrib/spi/moddatetime--unpackaged--1.0.sql
+++ b/contrib/spi/moddatetime--unpackaged--1.0.sql
@@ -1,3 +1,6 @@
 /* contrib/spi/moddatetime--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION moddatetime" to load this file. \quit
+
 ALTER EXTENSION moddatetime ADD function moddatetime();
diff --git a/contrib/spi/refint--1.0.sql b/contrib/spi/refint--1.0.sql
index 9e5d931df5e..faf797c2157 100644
--- a/contrib/spi/refint--1.0.sql
+++ b/contrib/spi/refint--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/spi/refint--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION refint" to load this file. \quit
+
 CREATE FUNCTION check_primary_key()
 RETURNS trigger
 AS 'MODULE_PATHNAME'
diff --git a/contrib/spi/refint--unpackaged--1.0.sql b/contrib/spi/refint--unpackaged--1.0.sql
index 54fece055a3..cd9c9b0c365 100644
--- a/contrib/spi/refint--unpackaged--1.0.sql
+++ b/contrib/spi/refint--unpackaged--1.0.sql
@@ -1,4 +1,7 @@
 /* contrib/spi/refint--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION refint" to load this file. \quit
+
 ALTER EXTENSION refint ADD function check_primary_key();
 ALTER EXTENSION refint ADD function check_foreign_key();
diff --git a/contrib/spi/timetravel--1.0.sql b/contrib/spi/timetravel--1.0.sql
index b68cf2f2475..c34ca09965b 100644
--- a/contrib/spi/timetravel--1.0.sql
+++ b/contrib/spi/timetravel--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/spi/timetravel--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION timetravel" to load this file. \quit
+
 CREATE FUNCTION timetravel()
 RETURNS trigger
 AS 'MODULE_PATHNAME'
diff --git a/contrib/spi/timetravel--unpackaged--1.0.sql b/contrib/spi/timetravel--unpackaged--1.0.sql
index e3716afe95a..dd07a133a50 100644
--- a/contrib/spi/timetravel--unpackaged--1.0.sql
+++ b/contrib/spi/timetravel--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/spi/timetravel--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION timetravel" to load this file. \quit
+
 ALTER EXTENSION timetravel ADD function timetravel();
 ALTER EXTENSION timetravel ADD function set_timetravel(name,integer);
 ALTER EXTENSION timetravel ADD function get_timetravel(name);
diff --git a/contrib/sslinfo/sslinfo--1.0.sql b/contrib/sslinfo/sslinfo--1.0.sql
index ef745a0a2e6..79ce656786f 100644
--- a/contrib/sslinfo/sslinfo--1.0.sql
+++ b/contrib/sslinfo/sslinfo--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/sslinfo/sslinfo--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
+
 CREATE FUNCTION ssl_client_serial() RETURNS numeric
 AS 'MODULE_PATHNAME', 'ssl_client_serial'
 LANGUAGE C STRICT;
diff --git a/contrib/sslinfo/sslinfo--unpackaged--1.0.sql b/contrib/sslinfo/sslinfo--unpackaged--1.0.sql
index befa96e908b..e4b868423b3 100644
--- a/contrib/sslinfo/sslinfo--unpackaged--1.0.sql
+++ b/contrib/sslinfo/sslinfo--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/sslinfo/sslinfo--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
+
 ALTER EXTENSION sslinfo ADD function ssl_client_serial();
 ALTER EXTENSION sslinfo ADD function ssl_is_used();
 ALTER EXTENSION sslinfo ADD function ssl_client_cert_present();
diff --git a/contrib/tablefunc/tablefunc--1.0.sql b/contrib/tablefunc/tablefunc--1.0.sql
index 7bf117cb5c0..8681ff47066 100644
--- a/contrib/tablefunc/tablefunc--1.0.sql
+++ b/contrib/tablefunc/tablefunc--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/tablefunc/tablefunc--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION tablefunc" to load this file. \quit
+
 CREATE FUNCTION normal_rand(int4, float8, float8)
 RETURNS setof float8
 AS 'MODULE_PATHNAME','normal_rand'
diff --git a/contrib/tablefunc/tablefunc--unpackaged--1.0.sql b/contrib/tablefunc/tablefunc--unpackaged--1.0.sql
index 20e09816e9d..e5e9619c52f 100644
--- a/contrib/tablefunc/tablefunc--unpackaged--1.0.sql
+++ b/contrib/tablefunc/tablefunc--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/tablefunc/tablefunc--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION tablefunc" to load this file. \quit
+
 ALTER EXTENSION tablefunc ADD function normal_rand(integer,double precision,double precision);
 ALTER EXTENSION tablefunc ADD function crosstab(text);
 ALTER EXTENSION tablefunc ADD type tablefunc_crosstab_2;
diff --git a/contrib/test_parser/test_parser--1.0.sql b/contrib/test_parser/test_parser--1.0.sql
index 5b8b04bb05b..06c94d353be 100644
--- a/contrib/test_parser/test_parser--1.0.sql
+++ b/contrib/test_parser/test_parser--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/test_parser/test_parser--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_parser" to load this file. \quit
+
 CREATE FUNCTION testprs_start(internal, int4)
 RETURNS internal
 AS 'MODULE_PATHNAME'
diff --git a/contrib/test_parser/test_parser--unpackaged--1.0.sql b/contrib/test_parser/test_parser--unpackaged--1.0.sql
index e240ab2b5bb..34120f2346b 100644
--- a/contrib/test_parser/test_parser--unpackaged--1.0.sql
+++ b/contrib/test_parser/test_parser--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/test_parser/test_parser--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_parser" to load this file. \quit
+
 ALTER EXTENSION test_parser ADD function testprs_start(internal,integer);
 ALTER EXTENSION test_parser ADD function testprs_getlexeme(internal,internal,internal);
 ALTER EXTENSION test_parser ADD function testprs_end(internal);
diff --git a/contrib/tsearch2/tsearch2--1.0.sql b/contrib/tsearch2/tsearch2--1.0.sql
index 369507e8f56..4777df8d914 100644
--- a/contrib/tsearch2/tsearch2--1.0.sql
+++ b/contrib/tsearch2/tsearch2--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/tsearch2/tsearch2--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION tsearch2" to load this file. \quit
+
 -- These domains are just to catch schema-qualified references to the
 -- old data types.
 CREATE DOMAIN tsvector AS pg_catalog.tsvector;
diff --git a/contrib/tsearch2/tsearch2--unpackaged--1.0.sql b/contrib/tsearch2/tsearch2--unpackaged--1.0.sql
index d04d5aa57e3..af970a4862f 100644
--- a/contrib/tsearch2/tsearch2--unpackaged--1.0.sql
+++ b/contrib/tsearch2/tsearch2--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/tsearch2/tsearch2--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION tsearch2" to load this file. \quit
+
 ALTER EXTENSION tsearch2 ADD type @extschema@.tsvector;
 ALTER EXTENSION tsearch2 ADD type @extschema@.tsquery;
 ALTER EXTENSION tsearch2 ADD type @extschema@.gtsvector;
diff --git a/contrib/unaccent/unaccent--1.0.sql b/contrib/unaccent/unaccent--1.0.sql
index b5909e0b556..9085ca473fb 100644
--- a/contrib/unaccent/unaccent--1.0.sql
+++ b/contrib/unaccent/unaccent--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/unaccent/unaccent--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION unaccent" to load this file. \quit
+
 CREATE FUNCTION unaccent(regdictionary, text)
 	RETURNS text
 	AS 'MODULE_PATHNAME', 'unaccent_dict'
diff --git a/contrib/unaccent/unaccent--unpackaged--1.0.sql b/contrib/unaccent/unaccent--unpackaged--1.0.sql
index eeb9c532f98..abd06983ac4 100644
--- a/contrib/unaccent/unaccent--unpackaged--1.0.sql
+++ b/contrib/unaccent/unaccent--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/unaccent/unaccent--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION unaccent" to load this file. \quit
+
 ALTER EXTENSION unaccent ADD function unaccent(regdictionary,text);
 ALTER EXTENSION unaccent ADD function unaccent(text);
 ALTER EXTENSION unaccent ADD function unaccent_init(internal);
diff --git a/contrib/uuid-ossp/uuid-ossp--1.0.sql b/contrib/uuid-ossp/uuid-ossp--1.0.sql
index 43ae0b38a0b..45ada1b23bc 100644
--- a/contrib/uuid-ossp/uuid-ossp--1.0.sql
+++ b/contrib/uuid-ossp/uuid-ossp--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/uuid-ossp/uuid-ossp--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION uuid-ossp" to load this file. \quit
+
 CREATE FUNCTION uuid_nil()
 RETURNS uuid
 AS 'MODULE_PATHNAME', 'uuid_nil'
diff --git a/contrib/uuid-ossp/uuid-ossp--unpackaged--1.0.sql b/contrib/uuid-ossp/uuid-ossp--unpackaged--1.0.sql
index bc984dd8c09..5c0dbfef9c0 100644
--- a/contrib/uuid-ossp/uuid-ossp--unpackaged--1.0.sql
+++ b/contrib/uuid-ossp/uuid-ossp--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/uuid-ossp/uuid-ossp--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION uuid-ossp" to load this file. \quit
+
 ALTER EXTENSION "uuid-ossp" ADD function uuid_nil();
 ALTER EXTENSION "uuid-ossp" ADD function uuid_ns_dns();
 ALTER EXTENSION "uuid-ossp" ADD function uuid_ns_url();
diff --git a/contrib/xml2/xml2--1.0.sql b/contrib/xml2/xml2--1.0.sql
index bc27dc89ca5..0b6afc63d05 100644
--- a/contrib/xml2/xml2--1.0.sql
+++ b/contrib/xml2/xml2--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/xml2/xml2--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION xml2" to load this file. \quit
+
 --SQL for XML parser
 
 -- deprecated old name for xml_is_well_formed
diff --git a/contrib/xml2/xml2--unpackaged--1.0.sql b/contrib/xml2/xml2--unpackaged--1.0.sql
index 1aa894a6192..b02dabffc2a 100644
--- a/contrib/xml2/xml2--unpackaged--1.0.sql
+++ b/contrib/xml2/xml2--unpackaged--1.0.sql
@@ -1,5 +1,8 @@
 /* contrib/xml2/xml2--unpackaged--1.0.sql */
 
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION xml2" to load this file. \quit
+
 ALTER EXTENSION xml2 ADD function xslt_process(text,text);
 ALTER EXTENSION xml2 ADD function xslt_process(text,text,text);
 ALTER EXTENSION xml2 ADD function xpath_table(text,text,text,text,text);
diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index 35a5ae8fd42..7079db3ed3f 100644
--- a/doc/src/sgml/extend.sgml
+++ b/doc/src/sgml/extend.sgml
@@ -522,6 +522,17 @@
      script files are implicitly executed within a transaction block.
     </para>
 
+    <para>
+     An extension's <acronym>SQL</> script files can also contain lines
+     beginning with <literal>\echo</>, which will be ignored (treated as
+     comments) by the extension mechanism.  This provision is commonly used
+     to throw an error if the script file is fed to <application>psql</>
+     rather than being loaded via <command>CREATE EXTENSION</> (see example
+     script below).  Without that, users might accidentally load the
+     extension's contents as <quote>loose</> objects rather than as an
+     extension, a state of affairs that's a bit tedious to recover from.
+    </para>
+
     <para>
      While the script files can contain any characters allowed by the specified
      encoding, control files should contain only plain ASCII, because there
@@ -808,6 +819,9 @@ SELECT * FROM pg_extension_update_paths('<replaceable>extension_name</>');
      The script file <filename>pair--1.0.sql</> looks like this:
 
 <programlisting><![CDATA[
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pair" to load this file. \quit
+
 CREATE TYPE pair AS ( k text, v text );
 
 CREATE OR REPLACE FUNCTION pair(anyelement, text)
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 3af15dd38bb..ba1e2c45cd9 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -33,6 +33,7 @@
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/objectaccess.h"
+#include "catalog/pg_collation.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_extension.h"
 #include "catalog/pg_namespace.h"
@@ -855,26 +856,39 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 	CurrentExtensionObject = extensionOid;
 	PG_TRY();
 	{
-		char	   *sql = read_extension_script_file(control, filename);
+		char	   *c_sql = read_extension_script_file(control, filename);
+		Datum		t_sql;
+
+		/* We use various functions that want to operate on text datums */
+		t_sql = CStringGetTextDatum(c_sql);
+
+		/*
+		 * Reduce any lines beginning with "\echo" to empty.  This allows
+		 * scripts to contain messages telling people not to run them via
+		 * psql, which has been found to be necessary due to old habits.
+		 */
+		t_sql = DirectFunctionCall4Coll(textregexreplace,
+										C_COLLATION_OID,
+										t_sql,
+										CStringGetTextDatum("^\\\\echo.*$"),
+										CStringGetTextDatum(""),
+										CStringGetTextDatum("ng"));
 
 		/*
 		 * If it's not relocatable, substitute the target schema name for
 		 * occcurrences of @extschema@.
 		 *
-		 * For a relocatable extension, we just run the script as-is. There
-		 * cannot be any need for @extschema@, else it wouldn't be
-		 * relocatable.
+		 * For a relocatable extension, we needn't do this.  There cannot be
+		 * any need for @extschema@, else it wouldn't be relocatable.
 		 */
 		if (!control->relocatable)
 		{
 			const char *qSchemaName = quote_identifier(schemaName);
 
-			sql = text_to_cstring(
-								  DatumGetTextPP(
-											DirectFunctionCall3(replace_text,
-													CStringGetTextDatum(sql),
-										  CStringGetTextDatum("@extschema@"),
-										 CStringGetTextDatum(qSchemaName))));
+			t_sql = DirectFunctionCall3(replace_text,
+										t_sql,
+										CStringGetTextDatum("@extschema@"),
+										CStringGetTextDatum(qSchemaName));
 		}
 
 		/*
@@ -883,15 +897,16 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 		 */
 		if (control->module_pathname)
 		{
-			sql = text_to_cstring(
-								  DatumGetTextPP(
-											DirectFunctionCall3(replace_text,
-													CStringGetTextDatum(sql),
-									  CStringGetTextDatum("MODULE_PATHNAME"),
-							CStringGetTextDatum(control->module_pathname))));
+			t_sql = DirectFunctionCall3(replace_text,
+										t_sql,
+										CStringGetTextDatum("MODULE_PATHNAME"),
+							CStringGetTextDatum(control->module_pathname));
 		}
 
-		execute_sql_string(sql, filename);
+		/* And now back to C string */
+		c_sql = text_to_cstring(DatumGetTextPP(t_sql));
+
+		execute_sql_string(c_sql, filename);
 	}
 	PG_CATCH();
 	{
-- 
GitLab