Hi, Thanks for your very good review!
Ibrar Ahmed <ibrar.ah...@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
*** 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); ! } } /*
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers