Review: create extension default_full_version

Started by Ibrar Ahmedabout 13 years ago7 messages
#1Ibrar Ahmed
ibrar.ahmad@gmail.com

Hi,

I looked at the discussion for this patch and the patch itself. Here
are my comments and observations about the patch.
What I got from the discussion is that the patch tries to implement a
mechanism to install extension from series of SQL scripts from
base/full version e.g. if a user wants to create an extension "1.1",
system should run v1.0 script followed by 1.0--1.1 script. In that
case we need to know about the base or full version which in the above
case is v1.0. So the patch added a defualt_full_version option in
extension control file.

Here are my comments about the patch

* Note: Patch does not apply cleanly on latest code base. You probably
need to re-base the code

ibrar@ibrar-laptop:~/work/postgresql$ patch -p1
<extension-default-full-version.v0.patch
patching file contrib/hstore/Makefile
Hunk #1 FAILED at 5.
1 out of 1 hunk FAILED -- saving rejects to file contrib/hstore/Makefile.rej
patching file contrib/hstore/hstore--1.1.sql
patching file contrib/hstore/hstore.control
patching file src/backend/commands/extension.c
Hunk #1 succeeded at 68 (offset 2 lines).
Hunk #2 succeeded at 508 (offset 2 lines).
Hunk #3 succeeded at 1295 (offset 2 lines).
Hunk #4 succeeded at 1316 (offset 2 lines).
Hunk #5 succeeded at 1473 (offset 3 lines).

* This is a user visible change so documentation change is required here.

* Also, You need to update the comment, because this code is now
handling default_full_version as well.

/*
* Determine the (unpackaged) version to update from, if any, and then
* figure out what sequence of update scripts we need to apply.
*/
if ((d_old_version && d_old_version->arg) || pcontrol->default_full_version)

* In case the "default_full_version" and VERSION in SQL are same then
we are getting a misleading error message i.e.

comment = 'data type for storing sets of (key, value) pairs'
default_version = '1.1'
default_full_version = '1.0'
module_pathname = '$libdir/hstore'
relocatable = true

postgres=# create EXTENSION hstore version '1.0';
ERROR: FROM version must be different from installation target version "1.0"

Error message is complaining about "FROM" clause which is not used in
the query. I think EXTENSION creation should not be blocked in case
"default_full_version" and VERSION are same. But if we want to block
that; error message should be meaningful.

* I noticed another issue with the patch.

In case we do not specify the default_full_version in control file
then this is the sequence of sql scripts.

postgres=# CREATE EXTENSION hstore version '1.3' from '1.0';
WARNING: /usr/local/pgsql/share/extension/hstore--1.0--1.1.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.1--1.2.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.2--1.3.sql
CREATE EXTENSION

But in case default_full_version = 1.0, then we are getting "ERROR:
could not stat file..." error message.

postgres=# CREATE EXTENSION hstore version '1.3' from '1.0';
WARNING: SCRIPT = /usr/local/pgsql/share/extension/hstore--1.0.sql
WARNING: SCRIPT =
/usr/local/pgsql/share/extension/hstore--1.0--1.2.sql
<<--- Why not 1.0--1.1
ERROR: could not stat file
"/usr/local/pgsql/share/extension/hstore--1.0--1.2.sql": No such file
or directory

This is because of missing version number i.e. first we're executing
1.0 followed by 1.0--1.2 not 1.0--1.1 but I think following should be
the right sequence

postgres=# CREATE EXTENSION hstore version '1.3' from '1.0';
WARNING: /usr/local/pgsql/share/extension/hstore--1.0.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.0--1.1.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.1--1.2.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.2--1.3.sql
CREATE EXTENSION

PS: I modified the code to get this result.

- IMHO there should be an SQL option along with the default_full_version; like.

postgres=# create EXTENSION hstore VERSION '1.1' FULL_VERSION '1.0';

- hstore regression is also failing.

-----------

Ibrar Ahmed

#2Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Ibrar Ahmed (#1)
1 attachment(s)
Re: Review: create extension default_full_version

Hi,

Thanks for your very good review!

Ibrar Ahmed <ibrar.ahmad@gmail.com> writes:

I looked at the discussion for this patch and the patch itself. Here
are my comments and observations about the patch.
What I got from the discussion is that the patch tries to implement a
mechanism to install extension from series of SQL scripts from
base/full version e.g. if a user wants to create an extension "1.1",
system should run v1.0 script followed by 1.0--1.1 script. In that
case we need to know about the base or full version which in the above
case is v1.0. So the patch added a defualt_full_version option in
extension control file.

Exactly, that was an idea from Robert and I implemented it quite
quickly. Too quickly as we can see from your testing report.

Here are my comments about the patch

* Note: Patch does not apply cleanly on latest code base. You probably
need to re-base the code

Done. The thing is that meanwhile another solution to the main problem
has been found: drop support for installing hstore 1.0. Attached patch
fixes the problem by reinstalling hstore--1.0.sql and re-enabling this
version, and removing the hstore--1.1.sql file now that it's enough to
just have hstore--1.0--1.1.sql to install directly (and by default) the
newer version.

I think we will have to decide about taking only the mechanism or both
the mechanism and the actual change for the hstore contrib.

* This is a user visible change so documentation change is required here.

Added coverage of the new parameter.

* Also, You need to update the comment, because this code is now
handling default_full_version as well.

/*
* Determine the (unpackaged) version to update from, if any, and then
* figure out what sequence of update scripts we need to apply.
*/
if ((d_old_version && d_old_version->arg) || pcontrol->default_full_version)

Done. I also fixed the bugs you reported here. Here's an edited version
of the new (fixed) output:

dim=# set client_min_messages to debug1;

dim=# create extension hstore version '1.0';
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--1.0.sql'
WARNING: => is deprecated as an operator name
CREATE EXTENSION

dim=# create extension hstore version '1.1';
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--1.0.sql'
WARNING: => is deprecated as an operator name
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--1.0--1.1.sql'
CREATE EXTENSION

dim=# create extension hstore;
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--1.0.sql'
WARNING: => is deprecated as an operator name
DETAIL: This name may be disallowed altogether in future versions of PostgreSQL.
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--1.0--1.1.sql'
CREATE EXTENSION

postgres=# CREATE EXTENSION hstore version '1.3' from '1.0';
WARNING: /usr/local/pgsql/share/extension/hstore--1.0--1.1.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.1--1.2.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.2--1.3.sql
CREATE EXTENSION

I liked your idea of extending the reporting about what files are used,
but of course we can't keep that at the WARNING level, so I made that
logging DEBUG1 in the attached patch.

postgres=# CREATE EXTENSION hstore version '1.3' from '1.0';

Please try that case again, I believe it's fixed in the attached.

- hstore regression is also failing.

That's because it doesn't cope anymore with the operator => warning, and
I left it this way because we have to decide about shipping hstore 1.0
once we have this patch in.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

extension-default-full-version.v1.patchtext/x-patchDownload
*** a/contrib/hstore/Makefile
--- b/contrib/hstore/Makefile
***************
*** 5,11 **** OBJS = hstore_io.o hstore_op.o hstore_gist.o hstore_gin.o hstore_compat.o \
  	crc32.o
  
  EXTENSION = hstore
! DATA = hstore--1.1.sql hstore--1.0--1.1.sql hstore--unpackaged--1.0.sql
  
  REGRESS = hstore
  
--- 5,11 ----
  	crc32.o
  
  EXTENSION = hstore
! DATA = hstore--1.0.sql hstore--1.0--1.1.sql hstore--unpackaged--1.0.sql
  
  REGRESS = hstore
  
*** /dev/null
--- b/contrib/hstore/hstore--1.0.sql
***************
*** 0 ****
--- 1,530 ----
+ /* 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)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_out(hstore)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_recv(internal)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_send(hstore)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE hstore (
+         INTERNALLENGTH = -1,
+         INPUT = hstore_in,
+         OUTPUT = hstore_out,
+         RECEIVE = hstore_recv,
+         SEND = hstore_send,
+         STORAGE = extended
+ );
+ 
+ CREATE FUNCTION hstore_version_diag(hstore)
+ RETURNS integer
+ AS 'MODULE_PATHNAME','hstore_version_diag'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION fetchval(hstore,text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','hstore_fetchval'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR -> (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text,
+ 	PROCEDURE = fetchval
+ );
+ 
+ CREATE FUNCTION slice_array(hstore,text[])
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_slice_to_array'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR -> (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = slice_array
+ );
+ 
+ CREATE FUNCTION slice(hstore,text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_slice_to_hstore'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION isexists(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION exist(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR ? (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text,
+ 	PROCEDURE = exist,
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION exists_any(hstore,text[])
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists_any'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR ?| (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = exists_any,
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION exists_all(hstore,text[])
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists_all'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR ?& (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = exists_all,
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION isdefined(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_defined'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION defined(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_defined'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION delete(hstore,text)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_delete'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION delete(hstore,text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_delete_array'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION delete(hstore,hstore)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_delete_hstore'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text,
+ 	PROCEDURE = delete
+ );
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = delete
+ );
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = delete
+ );
+ 
+ CREATE FUNCTION hs_concat(hstore,hstore)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_concat'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR || (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_concat
+ );
+ 
+ CREATE FUNCTION hs_contains(hstore,hstore)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_contains'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hs_contained(hstore,hstore)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_contained'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR @> (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contains,
+ 	COMMUTATOR = '<@',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR <@ (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contained,
+ 	COMMUTATOR = '@>',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ -- obsolete:
+ CREATE OPERATOR @ (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contains,
+ 	COMMUTATOR = '~',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR ~ (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contained,
+ 	COMMUTATOR = '@',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION tconvert(text,text)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_from_text'
+ LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
+ 
+ CREATE FUNCTION hstore(text,text)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_from_text'
+ LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
+ 
+ CREATE OPERATOR => (
+ 	LEFTARG = text,
+ 	RIGHTARG = text,
+ 	PROCEDURE = hstore
+ );
+ 
+ CREATE FUNCTION hstore(text[],text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME', 'hstore_from_arrays'
+ LANGUAGE C IMMUTABLE; -- not STRICT; allows (keys,null)
+ 
+ CREATE FUNCTION hstore(text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME', 'hstore_from_array'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE CAST (text[] AS hstore)
+   WITH FUNCTION hstore(text[]);
+ 
+ CREATE FUNCTION hstore(record)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME', 'hstore_from_record'
+ LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::recordtype)
+ 
+ CREATE FUNCTION hstore_to_array(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_to_array'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR %% (
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_to_array
+ );
+ 
+ CREATE FUNCTION hstore_to_matrix(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_to_matrix'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR %# (
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_to_matrix
+ );
+ 
+ CREATE FUNCTION akeys(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_akeys'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION avals(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_avals'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION skeys(hstore)
+ RETURNS setof text
+ AS 'MODULE_PATHNAME','hstore_skeys'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION svals(hstore)
+ RETURNS setof text
+ AS 'MODULE_PATHNAME','hstore_svals'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION each(IN hs hstore,
+     OUT key text,
+     OUT value text)
+ RETURNS SETOF record
+ AS 'MODULE_PATHNAME','hstore_each'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION populate_record(anyelement,hstore)
+ RETURNS anyelement
+ AS 'MODULE_PATHNAME', 'hstore_populate_record'
+ LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::rectype,hstore)
+ 
+ CREATE OPERATOR #= (
+ 	LEFTARG = anyelement,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = populate_record
+ );
+ 
+ -- btree support
+ 
+ CREATE FUNCTION hstore_eq(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_eq'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_ne(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_ne'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_gt(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_gt'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_ge(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_ge'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_lt(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_lt'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_le(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_le'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_cmp(hstore,hstore)
+ RETURNS integer
+ AS 'MODULE_PATHNAME','hstore_cmp'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR = (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_eq,
+        COMMUTATOR = =,
+        NEGATOR = <>,
+        RESTRICT = eqsel,
+        JOIN = eqjoinsel,
+        MERGES,
+        HASHES
+ );
+ CREATE OPERATOR <> (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_ne,
+        COMMUTATOR = <>,
+        NEGATOR = =,
+        RESTRICT = neqsel,
+        JOIN = neqjoinsel
+ );
+ 
+ -- the comparison operators have funky names (and are undocumented)
+ -- in an attempt to discourage anyone from actually using them. they
+ -- only exist to support the btree opclass
+ 
+ CREATE OPERATOR #<# (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_lt,
+        COMMUTATOR = #>#,
+        NEGATOR = #>=#,
+        RESTRICT = scalarltsel,
+        JOIN = scalarltjoinsel
+ );
+ CREATE OPERATOR #<=# (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_le,
+        COMMUTATOR = #>=#,
+        NEGATOR = #>#,
+        RESTRICT = scalarltsel,
+        JOIN = scalarltjoinsel
+ );
+ CREATE OPERATOR #># (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_gt,
+        COMMUTATOR = #<#,
+        NEGATOR = #<=#,
+        RESTRICT = scalargtsel,
+        JOIN = scalargtjoinsel
+ );
+ CREATE OPERATOR #>=# (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_ge,
+        COMMUTATOR = #<=#,
+        NEGATOR = #<#,
+        RESTRICT = scalargtsel,
+        JOIN = scalargtjoinsel
+ );
+ 
+ CREATE OPERATOR CLASS btree_hstore_ops
+ DEFAULT FOR TYPE hstore USING btree
+ AS
+ 	OPERATOR	1	#<# ,
+ 	OPERATOR	2	#<=# ,
+ 	OPERATOR	3	= ,
+ 	OPERATOR	4	#>=# ,
+ 	OPERATOR	5	#># ,
+ 	FUNCTION	1	hstore_cmp(hstore,hstore);
+ 
+ -- hash support
+ 
+ CREATE FUNCTION hstore_hash(hstore)
+ RETURNS integer
+ AS 'MODULE_PATHNAME','hstore_hash'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR CLASS hash_hstore_ops
+ DEFAULT FOR TYPE hstore USING hash
+ AS
+ 	OPERATOR	1	= ,
+ 	FUNCTION	1	hstore_hash(hstore);
+ 
+ -- GiST support
+ 
+ CREATE TYPE ghstore;
+ 
+ CREATE FUNCTION ghstore_in(cstring)
+ RETURNS ghstore
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION ghstore_out(ghstore)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE ghstore (
+         INTERNALLENGTH = -1,
+         INPUT = ghstore_in,
+         OUTPUT = ghstore_out
+ );
+ 
+ CREATE FUNCTION ghstore_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_union(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_same(internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_consistent(internal,internal,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE OPERATOR CLASS gist_hstore_ops
+ DEFAULT FOR TYPE hstore USING gist
+ AS
+ 	OPERATOR        7       @> ,
+ 	OPERATOR        9       ?(hstore,text) ,
+ 	OPERATOR        10      ?|(hstore,text[]) ,
+ 	OPERATOR        11      ?&(hstore,text[]) ,
+         --OPERATOR        8       <@ ,
+         OPERATOR        13      @ ,
+         --OPERATOR        14      ~ ,
+         FUNCTION        1       ghstore_consistent (internal, internal, int, oid, internal),
+         FUNCTION        2       ghstore_union (internal, internal),
+         FUNCTION        3       ghstore_compress (internal),
+         FUNCTION        4       ghstore_decompress (internal),
+         FUNCTION        5       ghstore_penalty (internal, internal, internal),
+         FUNCTION        6       ghstore_picksplit (internal, internal),
+         FUNCTION        7       ghstore_same (internal, internal, internal),
+         STORAGE         ghstore;
+ 
+ -- GIN support
+ 
+ CREATE FUNCTION gin_extract_hstore(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION gin_extract_hstore_query(internal, internal, int2, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE OPERATOR CLASS gin_hstore_ops
+ DEFAULT FOR TYPE hstore USING gin
+ AS
+ 	OPERATOR        7       @>,
+ 	OPERATOR        9       ?(hstore,text),
+ 	OPERATOR        10      ?|(hstore,text[]),
+ 	OPERATOR        11      ?&(hstore,text[]),
+ 	FUNCTION        1       bttextcmp(text,text),
+ 	FUNCTION        2       gin_extract_hstore(internal, internal),
+ 	FUNCTION        3       gin_extract_hstore_query(internal, internal, int2, internal, internal),
+ 	FUNCTION        4       gin_consistent_hstore(internal, int2, internal, int4, internal, internal),
+ 	STORAGE         text;
*** a/contrib/hstore/hstore--1.1.sql
--- /dev/null
***************
*** 1,524 ****
- /* contrib/hstore/hstore--1.1.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)
- RETURNS hstore
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_out(hstore)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_recv(internal)
- RETURNS hstore
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_send(hstore)
- RETURNS bytea
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE hstore (
-         INTERNALLENGTH = -1,
-         INPUT = hstore_in,
-         OUTPUT = hstore_out,
-         RECEIVE = hstore_recv,
-         SEND = hstore_send,
-         STORAGE = extended
- );
- 
- CREATE FUNCTION hstore_version_diag(hstore)
- RETURNS integer
- AS 'MODULE_PATHNAME','hstore_version_diag'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION fetchval(hstore,text)
- RETURNS text
- AS 'MODULE_PATHNAME','hstore_fetchval'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR -> (
- 	LEFTARG = hstore,
- 	RIGHTARG = text,
- 	PROCEDURE = fetchval
- );
- 
- CREATE FUNCTION slice_array(hstore,text[])
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_slice_to_array'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR -> (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = slice_array
- );
- 
- CREATE FUNCTION slice(hstore,text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_slice_to_hstore'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION isexists(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION exist(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR ? (
- 	LEFTARG = hstore,
- 	RIGHTARG = text,
- 	PROCEDURE = exist,
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION exists_any(hstore,text[])
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists_any'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR ?| (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = exists_any,
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION exists_all(hstore,text[])
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists_all'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR ?& (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = exists_all,
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION isdefined(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_defined'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION defined(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_defined'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION delete(hstore,text)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_delete'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION delete(hstore,text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_delete_array'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION delete(hstore,hstore)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_delete_hstore'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = hstore,
- 	RIGHTARG = text,
- 	PROCEDURE = delete
- );
- 
- CREATE OPERATOR - (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = delete
- );
- 
- CREATE OPERATOR - (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = delete
- );
- 
- CREATE FUNCTION hs_concat(hstore,hstore)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_concat'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR || (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_concat
- );
- 
- CREATE FUNCTION hs_contains(hstore,hstore)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_contains'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hs_contained(hstore,hstore)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_contained'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR @> (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contains,
- 	COMMUTATOR = '<@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR <@ (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contained,
- 	COMMUTATOR = '@>',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- -- obsolete:
- CREATE OPERATOR @ (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contains,
- 	COMMUTATOR = '~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~ (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contained,
- 	COMMUTATOR = '@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION tconvert(text,text)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_from_text'
- LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
- 
- CREATE FUNCTION hstore(text,text)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_from_text'
- LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
- 
- CREATE FUNCTION hstore(text[],text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME', 'hstore_from_arrays'
- LANGUAGE C IMMUTABLE; -- not STRICT; allows (keys,null)
- 
- CREATE FUNCTION hstore(text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME', 'hstore_from_array'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE CAST (text[] AS hstore)
-   WITH FUNCTION hstore(text[]);
- 
- CREATE FUNCTION hstore(record)
- RETURNS hstore
- AS 'MODULE_PATHNAME', 'hstore_from_record'
- LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::recordtype)
- 
- CREATE FUNCTION hstore_to_array(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_to_array'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR %% (
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_to_array
- );
- 
- CREATE FUNCTION hstore_to_matrix(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_to_matrix'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR %# (
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_to_matrix
- );
- 
- CREATE FUNCTION akeys(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_akeys'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION avals(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_avals'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION skeys(hstore)
- RETURNS setof text
- AS 'MODULE_PATHNAME','hstore_skeys'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION svals(hstore)
- RETURNS setof text
- AS 'MODULE_PATHNAME','hstore_svals'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION each(IN hs hstore,
-     OUT key text,
-     OUT value text)
- RETURNS SETOF record
- AS 'MODULE_PATHNAME','hstore_each'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION populate_record(anyelement,hstore)
- RETURNS anyelement
- AS 'MODULE_PATHNAME', 'hstore_populate_record'
- LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::rectype,hstore)
- 
- CREATE OPERATOR #= (
- 	LEFTARG = anyelement,
- 	RIGHTARG = hstore,
- 	PROCEDURE = populate_record
- );
- 
- -- btree support
- 
- CREATE FUNCTION hstore_eq(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_eq'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_ne(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_ne'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_gt(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_gt'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_ge(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_ge'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_lt(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_lt'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_le(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_le'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_cmp(hstore,hstore)
- RETURNS integer
- AS 'MODULE_PATHNAME','hstore_cmp'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR = (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_eq,
-        COMMUTATOR = =,
-        NEGATOR = <>,
-        RESTRICT = eqsel,
-        JOIN = eqjoinsel,
-        MERGES,
-        HASHES
- );
- CREATE OPERATOR <> (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_ne,
-        COMMUTATOR = <>,
-        NEGATOR = =,
-        RESTRICT = neqsel,
-        JOIN = neqjoinsel
- );
- 
- -- the comparison operators have funky names (and are undocumented)
- -- in an attempt to discourage anyone from actually using them. they
- -- only exist to support the btree opclass
- 
- CREATE OPERATOR #<# (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_lt,
-        COMMUTATOR = #>#,
-        NEGATOR = #>=#,
-        RESTRICT = scalarltsel,
-        JOIN = scalarltjoinsel
- );
- CREATE OPERATOR #<=# (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_le,
-        COMMUTATOR = #>=#,
-        NEGATOR = #>#,
-        RESTRICT = scalarltsel,
-        JOIN = scalarltjoinsel
- );
- CREATE OPERATOR #># (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_gt,
-        COMMUTATOR = #<#,
-        NEGATOR = #<=#,
-        RESTRICT = scalargtsel,
-        JOIN = scalargtjoinsel
- );
- CREATE OPERATOR #>=# (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_ge,
-        COMMUTATOR = #<=#,
-        NEGATOR = #<#,
-        RESTRICT = scalargtsel,
-        JOIN = scalargtjoinsel
- );
- 
- CREATE OPERATOR CLASS btree_hstore_ops
- DEFAULT FOR TYPE hstore USING btree
- AS
- 	OPERATOR	1	#<# ,
- 	OPERATOR	2	#<=# ,
- 	OPERATOR	3	= ,
- 	OPERATOR	4	#>=# ,
- 	OPERATOR	5	#># ,
- 	FUNCTION	1	hstore_cmp(hstore,hstore);
- 
- -- hash support
- 
- CREATE FUNCTION hstore_hash(hstore)
- RETURNS integer
- AS 'MODULE_PATHNAME','hstore_hash'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR CLASS hash_hstore_ops
- DEFAULT FOR TYPE hstore USING hash
- AS
- 	OPERATOR	1	= ,
- 	FUNCTION	1	hstore_hash(hstore);
- 
- -- GiST support
- 
- CREATE TYPE ghstore;
- 
- CREATE FUNCTION ghstore_in(cstring)
- RETURNS ghstore
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION ghstore_out(ghstore)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE ghstore (
-         INTERNALLENGTH = -1,
-         INPUT = ghstore_in,
-         OUTPUT = ghstore_out
- );
- 
- CREATE FUNCTION ghstore_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_union(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_same(internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_consistent(internal,internal,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE OPERATOR CLASS gist_hstore_ops
- DEFAULT FOR TYPE hstore USING gist
- AS
- 	OPERATOR        7       @> ,
- 	OPERATOR        9       ?(hstore,text) ,
- 	OPERATOR        10      ?|(hstore,text[]) ,
- 	OPERATOR        11      ?&(hstore,text[]) ,
-         --OPERATOR        8       <@ ,
-         OPERATOR        13      @ ,
-         --OPERATOR        14      ~ ,
-         FUNCTION        1       ghstore_consistent (internal, internal, int, oid, internal),
-         FUNCTION        2       ghstore_union (internal, internal),
-         FUNCTION        3       ghstore_compress (internal),
-         FUNCTION        4       ghstore_decompress (internal),
-         FUNCTION        5       ghstore_penalty (internal, internal, internal),
-         FUNCTION        6       ghstore_picksplit (internal, internal),
-         FUNCTION        7       ghstore_same (internal, internal, internal),
-         STORAGE         ghstore;
- 
- -- GIN support
- 
- CREATE FUNCTION gin_extract_hstore(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION gin_extract_hstore_query(internal, internal, int2, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE OPERATOR CLASS gin_hstore_ops
- DEFAULT FOR TYPE hstore USING gin
- AS
- 	OPERATOR        7       @>,
- 	OPERATOR        9       ?(hstore,text),
- 	OPERATOR        10      ?|(hstore,text[]),
- 	OPERATOR        11      ?&(hstore,text[]),
- 	FUNCTION        1       bttextcmp(text,text),
- 	FUNCTION        2       gin_extract_hstore(internal, internal),
- 	FUNCTION        3       gin_extract_hstore_query(internal, internal, int2, internal, internal),
- 	FUNCTION        4       gin_consistent_hstore(internal, int2, internal, int4, internal, internal),
- 	STORAGE         text;
--- 0 ----
*** a/contrib/hstore/hstore.control
--- b/contrib/hstore/hstore.control
***************
*** 1,5 ****
--- 1,6 ----
  # hstore extension
  comment = 'data type for storing sets of (key, value) pairs'
  default_version = '1.1'
+ default_full_version = '1.0'
  module_pathname = '$libdir/hstore'
  relocatable = true
*** a/doc/src/sgml/extend.sgml
--- b/doc/src/sgml/extend.sgml
***************
*** 423,428 ****
--- 423,443 ----
       </varlistentry>
  
       <varlistentry>
+       <term><varname>default_full_version</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+         This option allows an extension author to avoid shiping all versions
+         scripts when shipping an extension. When a version is requested and
+         the matching script does not exist on disk,
+         set <replaceable>default_full_version</replaceable> to the first
+         script you still ship and PostgreSQL will apply the intermediate
+         upgrade script as per the <command>ALTER EXTENSION UPDATE</command>
+         command.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><varname>comment</varname> (<type>string</type>)</term>
        <listitem>
         <para>
*** a/src/backend/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 68,73 **** typedef struct ExtensionControlFile
--- 68,74 ----
  	char	   *name;			/* name of the extension */
  	char	   *directory;		/* directory for script files */
  	char	   *default_version;	/* default install target version, if any */
+ 	char	   *default_full_version;	/* default install source version, if any */
  	char	   *module_pathname;	/* string to substitute for MODULE_PATHNAME */
  	char	   *comment;		/* comment, if any */
  	char	   *schema;			/* target schema (allowed if !relocatable) */
***************
*** 507,512 **** parse_extension_control_file(ExtensionControlFile *control,
--- 508,517 ----
  
  			control->default_version = pstrdup(item->value);
  		}
+ 		else if (strcmp(item->name, "default_full_version") == 0)
+ 		{
+ 			control->default_full_version = pstrdup(item->value);
+ 		}
  		else if (strcmp(item->name, "module_pathname") == 0)
  		{
  			control->module_pathname = pstrdup(item->value);
***************
*** 804,809 **** execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
--- 809,816 ----
  
  	filename = get_extension_script_filename(control, from_version, version);
  
+ 	elog(DEBUG1, "execute_extension_script: '%s'", filename);
+ 
  	/*
  	 * Force client_min_messages and log_min_messages to be at least WARNING,
  	 * so that we won't spam the user with useless NOTICE messages from common
***************
*** 1289,1328 **** CreateExtension(CreateExtensionStmt *stmt)
  	/*
  	 * Determine the (unpackaged) version to update from, if any, and then
  	 * figure out what sequence of update scripts we need to apply.
  	 */
! 	if (d_old_version && d_old_version->arg)
  	{
! 		oldVersionName = strVal(d_old_version->arg);
! 		check_valid_version_name(oldVersionName);
  
! 		if (strcmp(oldVersionName, versionName) == 0)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 					 errmsg("FROM version must be different from installation target version \"%s\"",
! 							versionName)));
  
! 		updateVersions = identify_update_path(pcontrol,
! 											  oldVersionName,
! 											  versionName);
  
! 		if (list_length(updateVersions) == 1)
  		{
! 			/*
! 			 * Simple case where there's just one update script to run. We
! 			 * will not need any follow-on update steps.
! 			 */
! 			Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
! 			updateVersions = NIL;
  		}
  		else
  		{
! 			/*
! 			 * Multi-step sequence.  We treat this as installing the version
! 			 * that is the target of the first script, followed by successive
! 			 * updates to the later versions.
! 			 */
! 			versionName = (char *) linitial(updateVersions);
! 			updateVersions = list_delete_first(updateVersions);
  		}
  	}
  	else
--- 1296,1370 ----
  	/*
  	 * Determine the (unpackaged) version to update from, if any, and then
  	 * figure out what sequence of update scripts we need to apply.
+ 	 *
+ 	 * When we have a default_full_version and the target is different from it,
+ 	 * apply the same algorithm to find a sequence of updates. If the user did
+ 	 * ask for a target version that happens to be the same as the
+ 	 * default_full_version, just install that one directly.
  	 */
! 	if ((d_old_version && d_old_version->arg) || pcontrol->default_full_version)
  	{
! 		bool unpackaged = (d_old_version && d_old_version->arg);
  
! 		if (unpackaged)
! 			oldVersionName = strVal(d_old_version->arg);
! 		else
! 			oldVersionName = pcontrol->default_full_version;
  
! 		check_valid_version_name(oldVersionName);
  
! 		if (strcmp(oldVersionName, versionName) == 0)
  		{
! 			if (unpackaged)
! 			{
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("FROM version must be different from installation target version \"%s\"",
! 								versionName)));
! 			}
! 			else
! 			{
! 				/*
! 				 * CREATE EXTENSION ... VERSION = default_full_version, just
! 				 * pretend we don't have a default_full_version for the
! 				 * remaining of the code here, as that's the behavior we want
! 				 * to see happening.
! 				 */
! 				pcontrol->default_full_version = NULL;
! 				oldVersionName = NULL;
! 				updateVersions = NIL;
! 			}
  		}
  		else
  		{
! 			/* oldVersionName != versionName */
! 			updateVersions = identify_update_path(pcontrol,
! 												  oldVersionName,
! 												  versionName);
! 		}
! 
! 		/* in the create from unpackaged case, reduce the update list */
! 		if (unpackaged)
! 		{
! 			if (list_length(updateVersions) == 1)
! 			{
! 				/*
! 				 * Simple case where there's just one update script to run. We
! 				 * will not need any follow-on update steps.
! 				 */
! 				Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
! 				updateVersions = NIL;
! 			}
! 			else
! 			{
! 				/*
! 				 * Multi-step sequence.  We treat this as installing the version
! 				 * that is the target of the first script, followed by successive
! 				 * updates to the later versions.
! 				 */
! 				versionName = (char *) linitial(updateVersions);
! 				updateVersions = list_delete_first(updateVersions);
! 			}
  		}
  	}
  	else
***************
*** 1458,1475 **** CreateExtension(CreateExtensionStmt *stmt)
  
  	/*
  	 * Execute the installation script file
! 	 */
! 	execute_extension_script(extensionOid, control,
! 							 oldVersionName, versionName,
! 							 requiredSchemas,
! 							 schemaName, schemaOid);
! 
! 	/*
  	 * If additional update scripts have to be executed, apply the updates as
  	 * though a series of ALTER EXTENSION UPDATE commands were given
  	 */
! 	ApplyExtensionUpdates(extensionOid, pcontrol,
! 						  versionName, updateVersions);
  }
  
  /*
--- 1500,1529 ----
  
  	/*
  	 * Execute the installation script file
! 	 *
  	 * If additional update scripts have to be executed, apply the updates as
  	 * though a series of ALTER EXTENSION UPDATE commands were given
  	 */
! 	if (pcontrol->default_full_version)
! 	{
! 		execute_extension_script(extensionOid, control,
! 								 NULL, oldVersionName,
! 								 requiredSchemas,
! 								 schemaName, schemaOid);
! 
! 		ApplyExtensionUpdates(extensionOid, pcontrol,
! 							  oldVersionName, updateVersions);
! 	}
! 	else
! 	{
! 		execute_extension_script(extensionOid, control,
! 								 oldVersionName, versionName,
! 								 requiredSchemas,
! 								 schemaName, schemaOid);
! 
! 		ApplyExtensionUpdates(extensionOid, pcontrol,
! 							  versionName, updateVersions);
! 	}
  }
  
  /*
#3Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Dimitri Fontaine (#2)
Re: Review: create extension default_full_version

On Mon, Dec 3, 2012 at 11:05 PM, Dimitri Fontaine <dimitri@2ndquadrant.fr>wrote:

Hi,

Thanks for your very good review!

Ibrar Ahmed <ibrar.ahmad@gmail.com> writes:

I looked at the discussion for this patch and the patch itself. Here
are my comments and observations about the patch.
What I got from the discussion is that the patch tries to implement a
mechanism to install extension from series of SQL scripts from
base/full version e.g. if a user wants to create an extension "1.1",
system should run v1.0 script followed by 1.0--1.1 script. In that
case we need to know about the base or full version which in the above
case is v1.0. So the patch added a defualt_full_version option in
extension control file.

Exactly, that was an idea from Robert and I implemented it quite
quickly. Too quickly as we can see from your testing report.

Here are my comments about the patch

* Note: Patch does not apply cleanly on latest code base. You probably
need to re-base the code

Done. The thing is that meanwhile another solution to the main problem
has been found: drop support for installing hstore 1.0. Attached patch
fixes the problem by reinstalling hstore--1.0.sql and re-enabling this
version, and removing the hstore--1.1.sql file now that it's enough to
just have hstore--1.0--1.1.sql to install directly (and by default) the
newer version.

I think we will have to decide about taking only the mechanism or both
the mechanism and the actual change for the hstore contrib.

* This is a user visible change so documentation change is required here.

Added coverage of the new parameter.

* Also, You need to update the comment, because this code is now
handling default_full_version as well.

/*
* Determine the (unpackaged) version to update from, if any, and

then

* figure out what sequence of update scripts we need to apply.
*/
if ((d_old_version && d_old_version->arg) ||

pcontrol->default_full_version)

Done. I also fixed the bugs you reported here. Here's an edited version
of the new (fixed) output:

dim=# set client_min_messages to debug1;

dim=# create extension hstore version '1.0';
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.0.sql'
WARNING: => is deprecated as an operator name
CREATE EXTENSION

dim=# create extension hstore version '1.1';
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.0.sql'
WARNING: => is deprecated as an operator name
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.0--1.1.sql'
CREATE EXTENSION

dim=# create extension hstore;
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.0.sql'
WARNING: => is deprecated as an operator name
DETAIL: This name may be disallowed altogether in future versions of
PostgreSQL.
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.0--1.1.sql'
CREATE EXTENSION

postgres=# CREATE EXTENSION hstore version '1.3' from '1.0';
WARNING: /usr/local/pgsql/share/extension/hstore--1.0--1.1.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.1--1.2.sql
WARNING: /usr/local/pgsql/share/extension/hstore--1.2--1.3.sql
CREATE EXTENSION

I liked your idea of extending the reporting about what files are used,
but of course we can't keep that at the WARNING level, so I made that
logging DEBUG1 in the attached patch.

postgres=# CREATE EXTENSION hstore version '1.3' from '1.0';

Please try that case again, I believe it's fixed in the attached.

I am still getting the same error message.

Without default_full_version
----------------------------------------

postgres=# CREATE EXTENSION hstore version '1.3' from '1.1';
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1--1.2.sql'
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.2--1.3.sql'
CREATE EXTENSION

With default_full_version = '1.1'
--------------------------------------------
postgres=# CREATE EXTENSION hstore version '1.3' from '1.1';
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1.sql'
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql'
*ERROR: could not stat file
"/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql": No such file or
directory*

I think there is an issue in this area of the code

if (pcontrol->default_full_version)
{
execute_extension_script(extensionOid, control,
<<-- 1.1.sql
NULL, oldVersionName,
requiredSchemas,
schemaName, schemaOid);

ApplyExtensionUpdates(extensionOid, pcontrol,
<<-- 1.1--1.3.sql (wrong)
oldVersionName, updateVersions);

The first statement is executing "1.1.sql" because oldVersionName = "1.1".
Keep in mind that versionName = "1.2" and updateVersions list contain only
version name "1.3". So in case of default_full_version you are ignoring *
versionName* which is *"1.2"* that is causing this error message
*
*
*ERROR: could not stat file
"/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql": No such file or
directory*

- hstore regression is also failing.

That's because it doesn't cope anymore with the operator => warning, and
I left it this way because we have to decide about shipping hstore 1.0
once we have this patch in.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

--
Ibrar Ahmed
EnterpriseDB http://www.enterprisedb.com

#4Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Ibrar Ahmed (#3)
1 attachment(s)
Re: Review: create extension default_full_version

Ibrar Ahmed <ibrar.ahmad@gmail.com> writes:

I am still getting the same error message.

With the attached patch (v2), it works well:

create extension hstore version '1.2' from 'unpackaged';
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--unpackaged--1.0.sql'
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--1.0--1.1.sql'
DEBUG: execute_extension_script: '/Users/dim/pgsql/ddl/share/extension/hstore--1.1--1.2.sql'
CREATE EXTENSION

You have to remember that the spelling FROM 'unpackaged version' really
means that we have previously installed a "loose" version of the
extension (just \i hstore.sql) and want to apply the upgrade path from
there.

We can't have FROM meaning the same thing as default_full_version.

With default_full_version = '1.1'
--------------------------------------------
postgres=# CREATE EXTENSION hstore version '1.3' from '1.1';
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1.sql'
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql'
*ERROR: could not stat file
"/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql": No such file or
directory*

That's nonetheless a bug and is fixed now:

-	if (pcontrol->default_full_version)
+	if (pcontrol->default_full_version && !unpackaged)

See attached.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

extension-default-full-version.v2.patchtext/x-patchDownload
*** a/contrib/hstore/Makefile
--- b/contrib/hstore/Makefile
***************
*** 5,11 **** OBJS = hstore_io.o hstore_op.o hstore_gist.o hstore_gin.o hstore_compat.o \
  	crc32.o
  
  EXTENSION = hstore
! DATA = hstore--1.1.sql hstore--1.0--1.1.sql hstore--unpackaged--1.0.sql
  
  REGRESS = hstore
  
--- 5,11 ----
  	crc32.o
  
  EXTENSION = hstore
! DATA = hstore--1.0.sql hstore--1.0--1.1.sql hstore--unpackaged--1.0.sql
  
  REGRESS = hstore
  
*** /dev/null
--- b/contrib/hstore/hstore--1.0.sql
***************
*** 0 ****
--- 1,530 ----
+ /* 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)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_out(hstore)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_recv(internal)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_send(hstore)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE hstore (
+         INTERNALLENGTH = -1,
+         INPUT = hstore_in,
+         OUTPUT = hstore_out,
+         RECEIVE = hstore_recv,
+         SEND = hstore_send,
+         STORAGE = extended
+ );
+ 
+ CREATE FUNCTION hstore_version_diag(hstore)
+ RETURNS integer
+ AS 'MODULE_PATHNAME','hstore_version_diag'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION fetchval(hstore,text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','hstore_fetchval'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR -> (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text,
+ 	PROCEDURE = fetchval
+ );
+ 
+ CREATE FUNCTION slice_array(hstore,text[])
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_slice_to_array'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR -> (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = slice_array
+ );
+ 
+ CREATE FUNCTION slice(hstore,text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_slice_to_hstore'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION isexists(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION exist(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR ? (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text,
+ 	PROCEDURE = exist,
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION exists_any(hstore,text[])
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists_any'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR ?| (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = exists_any,
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION exists_all(hstore,text[])
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_exists_all'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR ?& (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = exists_all,
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION isdefined(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_defined'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION defined(hstore,text)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_defined'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION delete(hstore,text)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_delete'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION delete(hstore,text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_delete_array'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION delete(hstore,hstore)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_delete_hstore'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text,
+ 	PROCEDURE = delete
+ );
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = text[],
+ 	PROCEDURE = delete
+ );
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = delete
+ );
+ 
+ CREATE FUNCTION hs_concat(hstore,hstore)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_concat'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR || (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_concat
+ );
+ 
+ CREATE FUNCTION hs_contains(hstore,hstore)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_contains'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hs_contained(hstore,hstore)
+ RETURNS bool
+ AS 'MODULE_PATHNAME','hstore_contained'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR @> (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contains,
+ 	COMMUTATOR = '<@',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR <@ (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contained,
+ 	COMMUTATOR = '@>',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ -- obsolete:
+ CREATE OPERATOR @ (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contains,
+ 	COMMUTATOR = '~',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR ~ (
+ 	LEFTARG = hstore,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = hs_contained,
+ 	COMMUTATOR = '@',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE FUNCTION tconvert(text,text)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_from_text'
+ LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
+ 
+ CREATE FUNCTION hstore(text,text)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME','hstore_from_text'
+ LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
+ 
+ CREATE OPERATOR => (
+ 	LEFTARG = text,
+ 	RIGHTARG = text,
+ 	PROCEDURE = hstore
+ );
+ 
+ CREATE FUNCTION hstore(text[],text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME', 'hstore_from_arrays'
+ LANGUAGE C IMMUTABLE; -- not STRICT; allows (keys,null)
+ 
+ CREATE FUNCTION hstore(text[])
+ RETURNS hstore
+ AS 'MODULE_PATHNAME', 'hstore_from_array'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE CAST (text[] AS hstore)
+   WITH FUNCTION hstore(text[]);
+ 
+ CREATE FUNCTION hstore(record)
+ RETURNS hstore
+ AS 'MODULE_PATHNAME', 'hstore_from_record'
+ LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::recordtype)
+ 
+ CREATE FUNCTION hstore_to_array(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_to_array'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR %% (
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_to_array
+ );
+ 
+ CREATE FUNCTION hstore_to_matrix(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_to_matrix'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR %# (
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_to_matrix
+ );
+ 
+ CREATE FUNCTION akeys(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_akeys'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION avals(hstore)
+ RETURNS text[]
+ AS 'MODULE_PATHNAME','hstore_avals'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION skeys(hstore)
+ RETURNS setof text
+ AS 'MODULE_PATHNAME','hstore_skeys'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION svals(hstore)
+ RETURNS setof text
+ AS 'MODULE_PATHNAME','hstore_svals'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION each(IN hs hstore,
+     OUT key text,
+     OUT value text)
+ RETURNS SETOF record
+ AS 'MODULE_PATHNAME','hstore_each'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION populate_record(anyelement,hstore)
+ RETURNS anyelement
+ AS 'MODULE_PATHNAME', 'hstore_populate_record'
+ LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::rectype,hstore)
+ 
+ CREATE OPERATOR #= (
+ 	LEFTARG = anyelement,
+ 	RIGHTARG = hstore,
+ 	PROCEDURE = populate_record
+ );
+ 
+ -- btree support
+ 
+ CREATE FUNCTION hstore_eq(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_eq'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_ne(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_ne'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_gt(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_gt'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_ge(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_ge'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_lt(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_lt'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_le(hstore,hstore)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','hstore_le'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION hstore_cmp(hstore,hstore)
+ RETURNS integer
+ AS 'MODULE_PATHNAME','hstore_cmp'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR = (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_eq,
+        COMMUTATOR = =,
+        NEGATOR = <>,
+        RESTRICT = eqsel,
+        JOIN = eqjoinsel,
+        MERGES,
+        HASHES
+ );
+ CREATE OPERATOR <> (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_ne,
+        COMMUTATOR = <>,
+        NEGATOR = =,
+        RESTRICT = neqsel,
+        JOIN = neqjoinsel
+ );
+ 
+ -- the comparison operators have funky names (and are undocumented)
+ -- in an attempt to discourage anyone from actually using them. they
+ -- only exist to support the btree opclass
+ 
+ CREATE OPERATOR #<# (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_lt,
+        COMMUTATOR = #>#,
+        NEGATOR = #>=#,
+        RESTRICT = scalarltsel,
+        JOIN = scalarltjoinsel
+ );
+ CREATE OPERATOR #<=# (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_le,
+        COMMUTATOR = #>=#,
+        NEGATOR = #>#,
+        RESTRICT = scalarltsel,
+        JOIN = scalarltjoinsel
+ );
+ CREATE OPERATOR #># (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_gt,
+        COMMUTATOR = #<#,
+        NEGATOR = #<=#,
+        RESTRICT = scalargtsel,
+        JOIN = scalargtjoinsel
+ );
+ CREATE OPERATOR #>=# (
+        LEFTARG = hstore,
+        RIGHTARG = hstore,
+        PROCEDURE = hstore_ge,
+        COMMUTATOR = #<=#,
+        NEGATOR = #<#,
+        RESTRICT = scalargtsel,
+        JOIN = scalargtjoinsel
+ );
+ 
+ CREATE OPERATOR CLASS btree_hstore_ops
+ DEFAULT FOR TYPE hstore USING btree
+ AS
+ 	OPERATOR	1	#<# ,
+ 	OPERATOR	2	#<=# ,
+ 	OPERATOR	3	= ,
+ 	OPERATOR	4	#>=# ,
+ 	OPERATOR	5	#># ,
+ 	FUNCTION	1	hstore_cmp(hstore,hstore);
+ 
+ -- hash support
+ 
+ CREATE FUNCTION hstore_hash(hstore)
+ RETURNS integer
+ AS 'MODULE_PATHNAME','hstore_hash'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR CLASS hash_hstore_ops
+ DEFAULT FOR TYPE hstore USING hash
+ AS
+ 	OPERATOR	1	= ,
+ 	FUNCTION	1	hstore_hash(hstore);
+ 
+ -- GiST support
+ 
+ CREATE TYPE ghstore;
+ 
+ CREATE FUNCTION ghstore_in(cstring)
+ RETURNS ghstore
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION ghstore_out(ghstore)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE ghstore (
+         INTERNALLENGTH = -1,
+         INPUT = ghstore_in,
+         OUTPUT = ghstore_out
+ );
+ 
+ CREATE FUNCTION ghstore_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_union(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_same(internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ghstore_consistent(internal,internal,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE OPERATOR CLASS gist_hstore_ops
+ DEFAULT FOR TYPE hstore USING gist
+ AS
+ 	OPERATOR        7       @> ,
+ 	OPERATOR        9       ?(hstore,text) ,
+ 	OPERATOR        10      ?|(hstore,text[]) ,
+ 	OPERATOR        11      ?&(hstore,text[]) ,
+         --OPERATOR        8       <@ ,
+         OPERATOR        13      @ ,
+         --OPERATOR        14      ~ ,
+         FUNCTION        1       ghstore_consistent (internal, internal, int, oid, internal),
+         FUNCTION        2       ghstore_union (internal, internal),
+         FUNCTION        3       ghstore_compress (internal),
+         FUNCTION        4       ghstore_decompress (internal),
+         FUNCTION        5       ghstore_penalty (internal, internal, internal),
+         FUNCTION        6       ghstore_picksplit (internal, internal),
+         FUNCTION        7       ghstore_same (internal, internal, internal),
+         STORAGE         ghstore;
+ 
+ -- GIN support
+ 
+ CREATE FUNCTION gin_extract_hstore(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION gin_extract_hstore_query(internal, internal, int2, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE OPERATOR CLASS gin_hstore_ops
+ DEFAULT FOR TYPE hstore USING gin
+ AS
+ 	OPERATOR        7       @>,
+ 	OPERATOR        9       ?(hstore,text),
+ 	OPERATOR        10      ?|(hstore,text[]),
+ 	OPERATOR        11      ?&(hstore,text[]),
+ 	FUNCTION        1       bttextcmp(text,text),
+ 	FUNCTION        2       gin_extract_hstore(internal, internal),
+ 	FUNCTION        3       gin_extract_hstore_query(internal, internal, int2, internal, internal),
+ 	FUNCTION        4       gin_consistent_hstore(internal, int2, internal, int4, internal, internal),
+ 	STORAGE         text;
*** a/contrib/hstore/hstore--1.1.sql
--- /dev/null
***************
*** 1,524 ****
- /* contrib/hstore/hstore--1.1.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)
- RETURNS hstore
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_out(hstore)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_recv(internal)
- RETURNS hstore
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_send(hstore)
- RETURNS bytea
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE hstore (
-         INTERNALLENGTH = -1,
-         INPUT = hstore_in,
-         OUTPUT = hstore_out,
-         RECEIVE = hstore_recv,
-         SEND = hstore_send,
-         STORAGE = extended
- );
- 
- CREATE FUNCTION hstore_version_diag(hstore)
- RETURNS integer
- AS 'MODULE_PATHNAME','hstore_version_diag'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION fetchval(hstore,text)
- RETURNS text
- AS 'MODULE_PATHNAME','hstore_fetchval'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR -> (
- 	LEFTARG = hstore,
- 	RIGHTARG = text,
- 	PROCEDURE = fetchval
- );
- 
- CREATE FUNCTION slice_array(hstore,text[])
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_slice_to_array'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR -> (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = slice_array
- );
- 
- CREATE FUNCTION slice(hstore,text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_slice_to_hstore'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION isexists(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION exist(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR ? (
- 	LEFTARG = hstore,
- 	RIGHTARG = text,
- 	PROCEDURE = exist,
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION exists_any(hstore,text[])
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists_any'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR ?| (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = exists_any,
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION exists_all(hstore,text[])
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_exists_all'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR ?& (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = exists_all,
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION isdefined(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_defined'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION defined(hstore,text)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_defined'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION delete(hstore,text)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_delete'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION delete(hstore,text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_delete_array'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION delete(hstore,hstore)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_delete_hstore'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = hstore,
- 	RIGHTARG = text,
- 	PROCEDURE = delete
- );
- 
- CREATE OPERATOR - (
- 	LEFTARG = hstore,
- 	RIGHTARG = text[],
- 	PROCEDURE = delete
- );
- 
- CREATE OPERATOR - (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = delete
- );
- 
- CREATE FUNCTION hs_concat(hstore,hstore)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_concat'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR || (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_concat
- );
- 
- CREATE FUNCTION hs_contains(hstore,hstore)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_contains'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hs_contained(hstore,hstore)
- RETURNS bool
- AS 'MODULE_PATHNAME','hstore_contained'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR @> (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contains,
- 	COMMUTATOR = '<@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR <@ (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contained,
- 	COMMUTATOR = '@>',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- -- obsolete:
- CREATE OPERATOR @ (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contains,
- 	COMMUTATOR = '~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~ (
- 	LEFTARG = hstore,
- 	RIGHTARG = hstore,
- 	PROCEDURE = hs_contained,
- 	COMMUTATOR = '@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE FUNCTION tconvert(text,text)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_from_text'
- LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
- 
- CREATE FUNCTION hstore(text,text)
- RETURNS hstore
- AS 'MODULE_PATHNAME','hstore_from_text'
- LANGUAGE C IMMUTABLE; -- not STRICT; needs to allow (key,NULL)
- 
- CREATE FUNCTION hstore(text[],text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME', 'hstore_from_arrays'
- LANGUAGE C IMMUTABLE; -- not STRICT; allows (keys,null)
- 
- CREATE FUNCTION hstore(text[])
- RETURNS hstore
- AS 'MODULE_PATHNAME', 'hstore_from_array'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE CAST (text[] AS hstore)
-   WITH FUNCTION hstore(text[]);
- 
- CREATE FUNCTION hstore(record)
- RETURNS hstore
- AS 'MODULE_PATHNAME', 'hstore_from_record'
- LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::recordtype)
- 
- CREATE FUNCTION hstore_to_array(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_to_array'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR %% (
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_to_array
- );
- 
- CREATE FUNCTION hstore_to_matrix(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_to_matrix'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR %# (
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_to_matrix
- );
- 
- CREATE FUNCTION akeys(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_akeys'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION avals(hstore)
- RETURNS text[]
- AS 'MODULE_PATHNAME','hstore_avals'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION skeys(hstore)
- RETURNS setof text
- AS 'MODULE_PATHNAME','hstore_skeys'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION svals(hstore)
- RETURNS setof text
- AS 'MODULE_PATHNAME','hstore_svals'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION each(IN hs hstore,
-     OUT key text,
-     OUT value text)
- RETURNS SETOF record
- AS 'MODULE_PATHNAME','hstore_each'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION populate_record(anyelement,hstore)
- RETURNS anyelement
- AS 'MODULE_PATHNAME', 'hstore_populate_record'
- LANGUAGE C IMMUTABLE; -- not STRICT; allows (null::rectype,hstore)
- 
- CREATE OPERATOR #= (
- 	LEFTARG = anyelement,
- 	RIGHTARG = hstore,
- 	PROCEDURE = populate_record
- );
- 
- -- btree support
- 
- CREATE FUNCTION hstore_eq(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_eq'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_ne(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_ne'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_gt(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_gt'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_ge(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_ge'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_lt(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_lt'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_le(hstore,hstore)
- RETURNS boolean
- AS 'MODULE_PATHNAME','hstore_le'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION hstore_cmp(hstore,hstore)
- RETURNS integer
- AS 'MODULE_PATHNAME','hstore_cmp'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR = (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_eq,
-        COMMUTATOR = =,
-        NEGATOR = <>,
-        RESTRICT = eqsel,
-        JOIN = eqjoinsel,
-        MERGES,
-        HASHES
- );
- CREATE OPERATOR <> (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_ne,
-        COMMUTATOR = <>,
-        NEGATOR = =,
-        RESTRICT = neqsel,
-        JOIN = neqjoinsel
- );
- 
- -- the comparison operators have funky names (and are undocumented)
- -- in an attempt to discourage anyone from actually using them. they
- -- only exist to support the btree opclass
- 
- CREATE OPERATOR #<# (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_lt,
-        COMMUTATOR = #>#,
-        NEGATOR = #>=#,
-        RESTRICT = scalarltsel,
-        JOIN = scalarltjoinsel
- );
- CREATE OPERATOR #<=# (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_le,
-        COMMUTATOR = #>=#,
-        NEGATOR = #>#,
-        RESTRICT = scalarltsel,
-        JOIN = scalarltjoinsel
- );
- CREATE OPERATOR #># (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_gt,
-        COMMUTATOR = #<#,
-        NEGATOR = #<=#,
-        RESTRICT = scalargtsel,
-        JOIN = scalargtjoinsel
- );
- CREATE OPERATOR #>=# (
-        LEFTARG = hstore,
-        RIGHTARG = hstore,
-        PROCEDURE = hstore_ge,
-        COMMUTATOR = #<=#,
-        NEGATOR = #<#,
-        RESTRICT = scalargtsel,
-        JOIN = scalargtjoinsel
- );
- 
- CREATE OPERATOR CLASS btree_hstore_ops
- DEFAULT FOR TYPE hstore USING btree
- AS
- 	OPERATOR	1	#<# ,
- 	OPERATOR	2	#<=# ,
- 	OPERATOR	3	= ,
- 	OPERATOR	4	#>=# ,
- 	OPERATOR	5	#># ,
- 	FUNCTION	1	hstore_cmp(hstore,hstore);
- 
- -- hash support
- 
- CREATE FUNCTION hstore_hash(hstore)
- RETURNS integer
- AS 'MODULE_PATHNAME','hstore_hash'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR CLASS hash_hstore_ops
- DEFAULT FOR TYPE hstore USING hash
- AS
- 	OPERATOR	1	= ,
- 	FUNCTION	1	hstore_hash(hstore);
- 
- -- GiST support
- 
- CREATE TYPE ghstore;
- 
- CREATE FUNCTION ghstore_in(cstring)
- RETURNS ghstore
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION ghstore_out(ghstore)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE ghstore (
-         INTERNALLENGTH = -1,
-         INPUT = ghstore_in,
-         OUTPUT = ghstore_out
- );
- 
- CREATE FUNCTION ghstore_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_union(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_same(internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ghstore_consistent(internal,internal,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE OPERATOR CLASS gist_hstore_ops
- DEFAULT FOR TYPE hstore USING gist
- AS
- 	OPERATOR        7       @> ,
- 	OPERATOR        9       ?(hstore,text) ,
- 	OPERATOR        10      ?|(hstore,text[]) ,
- 	OPERATOR        11      ?&(hstore,text[]) ,
-         --OPERATOR        8       <@ ,
-         OPERATOR        13      @ ,
-         --OPERATOR        14      ~ ,
-         FUNCTION        1       ghstore_consistent (internal, internal, int, oid, internal),
-         FUNCTION        2       ghstore_union (internal, internal),
-         FUNCTION        3       ghstore_compress (internal),
-         FUNCTION        4       ghstore_decompress (internal),
-         FUNCTION        5       ghstore_penalty (internal, internal, internal),
-         FUNCTION        6       ghstore_picksplit (internal, internal),
-         FUNCTION        7       ghstore_same (internal, internal, internal),
-         STORAGE         ghstore;
- 
- -- GIN support
- 
- CREATE FUNCTION gin_extract_hstore(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION gin_extract_hstore_query(internal, internal, int2, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE OPERATOR CLASS gin_hstore_ops
- DEFAULT FOR TYPE hstore USING gin
- AS
- 	OPERATOR        7       @>,
- 	OPERATOR        9       ?(hstore,text),
- 	OPERATOR        10      ?|(hstore,text[]),
- 	OPERATOR        11      ?&(hstore,text[]),
- 	FUNCTION        1       bttextcmp(text,text),
- 	FUNCTION        2       gin_extract_hstore(internal, internal),
- 	FUNCTION        3       gin_extract_hstore_query(internal, internal, int2, internal, internal),
- 	FUNCTION        4       gin_consistent_hstore(internal, int2, internal, int4, internal, internal),
- 	STORAGE         text;
--- 0 ----
*** a/contrib/hstore/hstore.control
--- b/contrib/hstore/hstore.control
***************
*** 1,5 ****
--- 1,6 ----
  # hstore extension
  comment = 'data type for storing sets of (key, value) pairs'
  default_version = '1.1'
+ default_full_version = '1.0'
  module_pathname = '$libdir/hstore'
  relocatable = true
*** a/doc/src/sgml/extend.sgml
--- b/doc/src/sgml/extend.sgml
***************
*** 423,428 ****
--- 423,443 ----
       </varlistentry>
  
       <varlistentry>
+       <term><varname>default_full_version</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+         This option allows an extension author to avoid shiping all versions
+         scripts when shipping an extension. When a version is requested and
+         the matching script does not exist on disk,
+         set <replaceable>default_full_version</replaceable> to the first
+         script you still ship and PostgreSQL will apply the intermediate
+         upgrade script as per the <command>ALTER EXTENSION UPDATE</command>
+         command.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><varname>comment</varname> (<type>string</type>)</term>
        <listitem>
         <para>
*** a/src/backend/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 68,73 **** typedef struct ExtensionControlFile
--- 68,74 ----
  	char	   *name;			/* name of the extension */
  	char	   *directory;		/* directory for script files */
  	char	   *default_version;	/* default install target version, if any */
+ 	char	   *default_full_version;	/* default install source version, if any */
  	char	   *module_pathname;	/* string to substitute for MODULE_PATHNAME */
  	char	   *comment;		/* comment, if any */
  	char	   *schema;			/* target schema (allowed if !relocatable) */
***************
*** 507,512 **** parse_extension_control_file(ExtensionControlFile *control,
--- 508,517 ----
  
  			control->default_version = pstrdup(item->value);
  		}
+ 		else if (strcmp(item->name, "default_full_version") == 0)
+ 		{
+ 			control->default_full_version = pstrdup(item->value);
+ 		}
  		else if (strcmp(item->name, "module_pathname") == 0)
  		{
  			control->module_pathname = pstrdup(item->value);
***************
*** 804,809 **** execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
--- 809,816 ----
  
  	filename = get_extension_script_filename(control, from_version, version);
  
+ 	elog(DEBUG1, "execute_extension_script: '%s'", filename);
+ 
  	/*
  	 * Force client_min_messages and log_min_messages to be at least WARNING,
  	 * so that we won't spam the user with useless NOTICE messages from common
***************
*** 1192,1197 **** CreateExtension(CreateExtensionStmt *stmt)
--- 1199,1205 ----
  	List	   *requiredSchemas;
  	Oid			extensionOid;
  	ListCell   *lc;
+ 	bool        unpackaged = false;
  
  	/* Check extension name validity before any filesystem access */
  	check_valid_extension_name(stmt->extname);
***************
*** 1289,1328 **** CreateExtension(CreateExtensionStmt *stmt)
  	/*
  	 * Determine the (unpackaged) version to update from, if any, and then
  	 * figure out what sequence of update scripts we need to apply.
  	 */
! 	if (d_old_version && d_old_version->arg)
  	{
! 		oldVersionName = strVal(d_old_version->arg);
! 		check_valid_version_name(oldVersionName);
  
! 		if (strcmp(oldVersionName, versionName) == 0)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 					 errmsg("FROM version must be different from installation target version \"%s\"",
! 							versionName)));
  
! 		updateVersions = identify_update_path(pcontrol,
! 											  oldVersionName,
! 											  versionName);
  
! 		if (list_length(updateVersions) == 1)
  		{
! 			/*
! 			 * Simple case where there's just one update script to run. We
! 			 * will not need any follow-on update steps.
! 			 */
! 			Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
! 			updateVersions = NIL;
  		}
  		else
  		{
! 			/*
! 			 * Multi-step sequence.  We treat this as installing the version
! 			 * that is the target of the first script, followed by successive
! 			 * updates to the later versions.
! 			 */
! 			versionName = (char *) linitial(updateVersions);
! 			updateVersions = list_delete_first(updateVersions);
  		}
  	}
  	else
--- 1297,1371 ----
  	/*
  	 * Determine the (unpackaged) version to update from, if any, and then
  	 * figure out what sequence of update scripts we need to apply.
+ 	 *
+ 	 * When we have a default_full_version and the target is different from it,
+ 	 * apply the same algorithm to find a sequence of updates. If the user did
+ 	 * ask for a target version that happens to be the same as the
+ 	 * default_full_version, just install that one directly.
  	 */
! 	if ((d_old_version && d_old_version->arg) || pcontrol->default_full_version)
  	{
! 		unpackaged = (d_old_version && d_old_version->arg);
  
! 		if (unpackaged)
! 			oldVersionName = strVal(d_old_version->arg);
! 		else
! 			oldVersionName = pcontrol->default_full_version;
  
! 		check_valid_version_name(oldVersionName);
  
! 		if (strcmp(oldVersionName, versionName) == 0)
  		{
! 			if (unpackaged)
! 			{
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("FROM version must be different from installation target version \"%s\"",
! 								versionName)));
! 			}
! 			else
! 			{
! 				/*
! 				 * CREATE EXTENSION ... VERSION = default_full_version, just
! 				 * pretend we don't have a default_full_version for the
! 				 * remaining of the code here, as that's the behavior we want
! 				 * to see happening.
! 				 */
! 				pcontrol->default_full_version = NULL;
! 				oldVersionName = NULL;
! 				updateVersions = NIL;
! 			}
  		}
  		else
  		{
! 			/* oldVersionName != versionName */
! 			updateVersions = identify_update_path(pcontrol,
! 												  oldVersionName,
! 												  versionName);
! 		}
! 
! 		/* in the create from unpackaged case, reduce the update list */
! 		if (unpackaged)
! 		{
! 			if (list_length(updateVersions) == 1)
! 			{
! 				/*
! 				 * Simple case where there's just one update script to run. We
! 				 * will not need any follow-on update steps.
! 				 */
! 				Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
! 				updateVersions = NIL;
! 			}
! 			else
! 			{
! 				/*
! 				 * Multi-step sequence.  We treat this as installing the version
! 				 * that is the target of the first script, followed by successive
! 				 * updates to the later versions.
! 				 */
! 				versionName = (char *) linitial(updateVersions);
! 				updateVersions = list_delete_first(updateVersions);
! 			}
  		}
  	}
  	else
***************
*** 1458,1475 **** CreateExtension(CreateExtensionStmt *stmt)
  
  	/*
  	 * Execute the installation script file
! 	 */
! 	execute_extension_script(extensionOid, control,
! 							 oldVersionName, versionName,
! 							 requiredSchemas,
! 							 schemaName, schemaOid);
! 
! 	/*
  	 * If additional update scripts have to be executed, apply the updates as
  	 * though a series of ALTER EXTENSION UPDATE commands were given
  	 */
! 	ApplyExtensionUpdates(extensionOid, pcontrol,
! 						  versionName, updateVersions);
  }
  
  /*
--- 1501,1530 ----
  
  	/*
  	 * Execute the installation script file
! 	 *
  	 * If additional update scripts have to be executed, apply the updates as
  	 * though a series of ALTER EXTENSION UPDATE commands were given
  	 */
! 	if (pcontrol->default_full_version && !unpackaged)
! 	{
! 		execute_extension_script(extensionOid, control,
! 								 NULL, oldVersionName,
! 								 requiredSchemas,
! 								 schemaName, schemaOid);
! 
! 		ApplyExtensionUpdates(extensionOid, pcontrol,
! 							  oldVersionName, updateVersions);
! 	}
! 	else
! 	{
! 		execute_extension_script(extensionOid, control,
! 								 oldVersionName, versionName,
! 								 requiredSchemas,
! 								 schemaName, schemaOid);
! 
! 		ApplyExtensionUpdates(extensionOid, pcontrol,
! 							  versionName, updateVersions);
! 	}
  }
  
  /*
#5Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Dimitri Fontaine (#4)
Re: Review: create extension default_full_version

On Tue, Dec 4, 2012 at 7:54 PM, Dimitri Fontaine <dimitri@2ndquadrant.fr>wrote:

Ibrar Ahmed <ibrar.ahmad@gmail.com> writes:

I am still getting the same error message.

With the attached patch (v2), it works well:

create extension hstore version '1.2' from 'unpackaged';
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--unpackaged--1.0.sql'
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.0--1.1.sql'
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.1--1.2.sql'
CREATE EXTENSION

You have to remember that the spelling FROM 'unpackaged version' really
means that we have previously installed a "loose" version of the
extension (just \i hstore.sql) and want to apply the upgrade path from
there.

We can't have FROM meaning the same thing as default_full_version.

I know.

With default_full_version = '1.1'
--------------------------------------------
postgres=# CREATE EXTENSION hstore version '1.3' from '1.1';
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1.sql'
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql'
*ERROR: could not stat file
"/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql": No such file or
directory*

That's nonetheless a bug and is fixed now:

-       if (pcontrol->default_full_version)
+       if (pcontrol->default_full_version && !unpackaged)

Thanks, I will look at this again in detail.

See attached.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

--
Ibrar Ahmed
EnterpriseDB http://www.enterprisedb.com

#6Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Ibrar Ahmed (#5)
Re: Review: create extension default_full_version

Now it works in most of the cases, here is one more point about the patch.

* In case we have hstore--1.3.sql file and want to install that file, but
failed because of default_full_version.

No default_full_version specified
-----------------------------------------------
postgres=# CREATE EXTENSION hstore version '1.3';
CREATE EXTENSION

default_full_version = 1.2
------------------------------------
postgres=# CREATE EXTENSION hstore version '1.3';
ERROR: could not stat file
"/usr/local/pgsql/share/extension/hstore--1.2.sql": No such file or
directory

If we don't want to address this issue at least we should give some
meaningful error message.

On Tue, Dec 4, 2012 at 4:46 PM, Ibrar Ahmed <ibrar.ahmad@gmail.com> wrote:

On Tue, Dec 4, 2012 at 7:54 PM, Dimitri Fontaine <dimitri@2ndquadrant.fr>wrote:

Ibrar Ahmed <ibrar.ahmad@gmail.com> writes:

I am still getting the same error message.

With the attached patch (v2), it works well:

create extension hstore version '1.2' from 'unpackaged';
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--unpackaged--1.0.sql'
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.0--1.1.sql'
DEBUG: execute_extension_script:
'/Users/dim/pgsql/ddl/share/extension/hstore--1.1--1.2.sql'
CREATE EXTENSION

You have to remember that the spelling FROM 'unpackaged version' really
means that we have previously installed a "loose" version of the
extension (just \i hstore.sql) and want to apply the upgrade path from
there.

We can't have FROM meaning the same thing as default_full_version.

I know.

With default_full_version = '1.1'
--------------------------------------------
postgres=# CREATE EXTENSION hstore version '1.3' from '1.1';
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1.sql'
DEBUG: execute_extension_script:
'/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql'
*ERROR: could not stat file
"/usr/local/pgsql/share/extension/hstore--1.1--1.3.sql": No such file or
directory*

That's nonetheless a bug and is fixed now:

-       if (pcontrol->default_full_version)
+       if (pcontrol->default_full_version && !unpackaged)

Thanks, I will look at this again in detail.

See attached.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

--
Ibrar Ahmed
EnterpriseDB http://www.enterprisedb.com

--
Ibrar Ahmed
EnterpriseDB http://www.enterprisedb.com

#7Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Ibrar Ahmed (#6)
Re: Review: create extension default_full_version

Ibrar Ahmed <ibrar.ahmad@gmail.com> writes:

* In case we have hstore--1.3.sql file and want to install that file, but
failed because of default_full_version.

That's now fixed, please see the Extension Templates patch at

/messages/by-id/m21uc8l4j8.fsf@2ndQuadrant.fr

Where you will even find regression tests for that problem.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers