diff options
Diffstat (limited to 'doc/src/sgml/extend.sgml')
-rw-r--r-- | doc/src/sgml/extend.sgml | 56 |
1 files changed, 41 insertions, 15 deletions
diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml index 4a883814d65..354ad7a8021 100644 --- a/doc/src/sgml/extend.sgml +++ b/doc/src/sgml/extend.sgml @@ -367,6 +367,32 @@ schema(s) its member objects are within. </para> + <sect2 id="extend-extensions-style"> + <title>Defining Extension Objects</title> + + <!-- XXX It's not enough to use qualified names, because one might write a + qualified name to an object that itself uses unqualified names. Many + information_schema functions have that defect, for example. However, + that's a defect in the referenced object, and relatively few queries + will be affected. Also, we direct applications to secure search_path + when connecting to an untrusted database; if applications do that, + they are immune to known attacks even if some extension refers to a + defective object. Therefore, guide extension authors as though core + PostgreSQL contained no such defect. --> + <para> + Widely-distributed extensions should assume little about the database + they occupy. In particular, unless you issued <literal>SET search_path = + pg_temp</literal>, assume each unqualified name could resolve to an + object that a malicious user has defined. Beware of constructs that + depend on <varname>search_path</varname> implicitly: <token>IN</token> + and <literal>CASE <replaceable>expression</replaceable> WHEN</literal> + always select an operator using the search path. In their place, use + <literal>OPERATOR(<replaceable>schema</replaceable>.=) ANY</literal> + and <literal>CASE WHEN <replaceable>expression</replaceable></literal>. + </para> + + </sect2> + <sect2> <title>Extension Files</title> @@ -858,24 +884,24 @@ SELECT * FROM pg_extension_update_paths('<replaceable>extension_name</>'); -- 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) -RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair'; +CREATE TYPE pair AS ( k pg_catalog.text, v pg_catalog.text ); -CREATE OR REPLACE FUNCTION pair(text, anyelement) -RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair'; +CREATE OR REPLACE FUNCTION pair(pg_catalog.text, pg_catalog.text) +RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::@extschema@.pair;'; -CREATE OR REPLACE FUNCTION pair(anyelement, anyelement) -RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair'; +CREATE OPERATOR ~> (LEFTARG = pg_catalog.text, + RIGHTARG = pg_catalog.text, PROCEDURE = pair); -CREATE OR REPLACE FUNCTION pair(text, text) -RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair;'; +-- "SET search_path" is easy to get right, but qualified names perform better. +CREATE OR REPLACE FUNCTION lower(pair) +RETURNS pair LANGUAGE SQL +AS 'SELECT ROW(lower($1.k), lower($1.v))::@extschema@.pair;' +SET search_path = pg_temp; -CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = anyelement, PROCEDURE = pair); -CREATE OPERATOR ~> (LEFTARG = anyelement, RIGHTARG = text, PROCEDURE = pair); -CREATE OPERATOR ~> (LEFTARG = anyelement, RIGHTARG = anyelement, PROCEDURE = pair); -CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = text, PROCEDURE = pair); +CREATE OR REPLACE FUNCTION pair_concat(pair, pair) +RETURNS pair LANGUAGE SQL +AS 'SELECT ROW($1.k OPERATOR(pg_catalog.||) $2.k, + $1.v OPERATOR(pg_catalog.||) $2.v)::@extschema@.pair;'; ]]> </programlisting> </para> @@ -887,7 +913,7 @@ CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = text, PROCEDURE = pair); # pair extension comment = 'A key/value pair data type' default_version = '1.0' -relocatable = true +relocatable = false </programlisting> </para> |