diff options
author | Shigeru Hanada | 2011-03-11 03:01:29 +0000 |
---|---|---|
committer | Shigeru Hanada | 2011-03-11 03:01:29 +0000 |
commit | 6ef467bfe4b55f28ab6c4c9414cab49795c1e6b0 (patch) | |
tree | 4e45e3dd0961562a621fc1bde5f3d7a221a6cff3 | |
parent | 6e1ebd8c8358fad0642c65d97205fe398b154ed2 (diff) | |
parent | 303b7fcd10a34d8c8b4c3e6e258faeaf107dcf92 (diff) |
Merge branch 'master' into postgresql_fdw
83 files changed, 919 insertions, 614 deletions
diff --git a/contrib/auth_delay/auth_delay.c b/contrib/auth_delay/auth_delay.c index 09191bd250..199de9bb39 100644 --- a/contrib/auth_delay/auth_delay.c +++ b/contrib/auth_delay/auth_delay.c @@ -2,7 +2,7 @@ * * auth_delay.c * - * Copyright (C) 2010, PostgreSQL Global Development Group + * Copyright (C) 2010-2011, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/auth_delay/auth_delay.c diff --git a/contrib/pg_test_fsync/pg_test_fsync.c b/contrib/pg_test_fsync/pg_test_fsync.c index d07548322c..49a7b3c2c0 100644 --- a/contrib/pg_test_fsync/pg_test_fsync.c +++ b/contrib/pg_test_fsync/pg_test_fsync.c @@ -23,7 +23,7 @@ #define XLOG_BLCKSZ_K (XLOG_BLCKSZ / 1024) #define LABEL_FORMAT " %-32s" -#define NA_FORMAT LABEL_FORMAT "%18s" +#define NA_FORMAT "%18s" #define OPS_FORMAT "%9.3f ops/sec" static const char *progname; @@ -134,6 +134,11 @@ handle_args(int argc, char *argv[]) } printf("%d operations per test\n", ops_per_test); +#if PG_O_DIRECT != 0 + printf("O_DIRECT supported on this platform for open_datasync and open_sync.\n"); +#else + printf("Direct I/O is not supported on this platform.\n"); +#endif } static void @@ -184,43 +189,19 @@ test_sync(int writes_per_op) /* * Test open_datasync if available */ -#ifdef OPEN_DATASYNC_FLAG - printf(LABEL_FORMAT, "open_datasync" -#if PG_O_DIRECT != 0 - " (non-direct I/O)*" -#endif - ); + printf(LABEL_FORMAT, "open_datasync"); fflush(stdout); - if ((tmpfile = open(filename, O_RDWR | O_DSYNC, 0)) == -1) - die("could not open output file"); - gettimeofday(&start_t, NULL); - for (ops = 0; ops < ops_per_test; ops++) - { - for (writes = 0; writes < writes_per_op; writes++) - if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ) - die("write failed"); - if (lseek(tmpfile, 0, SEEK_SET) == -1) - die("seek failed"); - } - gettimeofday(&stop_t, NULL); - close(tmpfile); - print_elapse(start_t, stop_t); - - /* - * If O_DIRECT is enabled, test that with open_datasync - */ -#if PG_O_DIRECT != 0 +#ifdef OPEN_DATASYNC_FLAG if ((tmpfile = open(filename, O_RDWR | O_DSYNC | PG_O_DIRECT, 0)) == -1) { - printf(NA_FORMAT, "o_direct", "n/a**\n"); + printf(NA_FORMAT, "n/a*\n"); fs_warning = true; } else { - printf(LABEL_FORMAT, "open_datasync (direct I/O)"); - fflush(stdout); - + if ((tmpfile = open(filename, O_RDWR | O_DSYNC | PG_O_DIRECT, 0)) == -1) + die("could not open output file"); gettimeofday(&start_t, NULL); for (ops = 0; ops < ops_per_test; ops++) { @@ -234,19 +215,17 @@ test_sync(int writes_per_op) close(tmpfile); print_elapse(start_t, stop_t); } -#endif - #else - printf(NA_FORMAT, "open_datasync", "n/a\n"); + printf(NA_FORMAT, "n/a\n"); #endif /* * Test fdatasync if available */ -#ifdef HAVE_FDATASYNC printf(LABEL_FORMAT, "fdatasync"); fflush(stdout); +#ifdef HAVE_FDATASYNC if ((tmpfile = open(filename, O_RDWR, 0)) == -1) die("could not open output file"); gettimeofday(&start_t, NULL); @@ -263,7 +242,7 @@ test_sync(int writes_per_op) close(tmpfile); print_elapse(start_t, stop_t); #else - printf(NA_FORMAT, "fdatasync", "n/a\n"); + printf(NA_FORMAT, "n/a\n"); #endif /* @@ -292,10 +271,10 @@ test_sync(int writes_per_op) /* * If fsync_writethrough is available, test as well */ -#ifdef HAVE_FSYNC_WRITETHROUGH printf(LABEL_FORMAT, "fsync_writethrough"); fflush(stdout); +#ifdef HAVE_FSYNC_WRITETHROUGH if ((tmpfile = open(filename, O_RDWR, 0)) == -1) die("could not open output file"); gettimeofday(&start_t, NULL); @@ -313,49 +292,23 @@ test_sync(int writes_per_op) close(tmpfile); print_elapse(start_t, stop_t); #else - printf(NA_FORMAT, "fsync_writethrough", "n/a\n"); + printf(NA_FORMAT, "n/a\n"); #endif /* * Test open_sync if available */ -#ifdef OPEN_SYNC_FLAG - printf(LABEL_FORMAT, "open_sync" -#if PG_O_DIRECT != 0 - " (non-direct I/O)*" -#endif - ); + printf(LABEL_FORMAT, "open_sync"); fflush(stdout); - if ((tmpfile = open(filename, O_RDWR | OPEN_SYNC_FLAG, 0)) == -1) - die("could not open output file"); - gettimeofday(&start_t, NULL); - for (ops = 0; ops < ops_per_test; ops++) - { - for (writes = 0; writes < writes_per_op; writes++) - if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ) - die("write failed"); - if (lseek(tmpfile, 0, SEEK_SET) == -1) - die("seek failed"); - } - gettimeofday(&stop_t, NULL); - close(tmpfile); - print_elapse(start_t, stop_t); - - /* - * If O_DIRECT is enabled, test that with open_sync - */ -#if PG_O_DIRECT != 0 +#ifdef OPEN_SYNC_FLAG if ((tmpfile = open(filename, O_RDWR | OPEN_SYNC_FLAG | PG_O_DIRECT, 0)) == -1) { - printf(NA_FORMAT, "o_direct", "n/a**\n"); + printf(NA_FORMAT, "n/a*\n"); fs_warning = true; } else { - printf(LABEL_FORMAT, "open_sync (direct I/O)"); - fflush(stdout); - gettimeofday(&start_t, NULL); for (ops = 0; ops < ops_per_test; ops++) { @@ -369,20 +322,13 @@ test_sync(int writes_per_op) close(tmpfile); print_elapse(start_t, stop_t); } -#endif - #else - printf(NA_FORMAT, "open_sync", "n/a\n"); -#endif - -#if defined(OPEN_DATASYNC_FLAG) || defined(OPEN_SYNC_FLAG) - if (PG_O_DIRECT != 0) - printf("* This non-direct I/O mode is not used by Postgres.\n"); + printf(NA_FORMAT, "n/a\n"); #endif if (fs_warning) { - printf("** This file system and its mount options do not support direct\n"); + printf("* This file system and its mount options do not support direct\n"); printf("I/O, e.g. ext4 in journaled mode.\n"); } } @@ -407,16 +353,16 @@ test_open_syncs(void) static void test_open_sync(const char *msg, int writes_size) { -#ifdef OPEN_SYNC_FLAG int tmpfile, ops, writes; + printf(LABEL_FORMAT, msg); + fflush(stdout); + +#ifdef OPEN_SYNC_FLAG if ((tmpfile = open(filename, O_RDWR | OPEN_SYNC_FLAG | PG_O_DIRECT, 0)) == -1) - printf(NA_FORMAT, "o_direct", "n/a**\n"); + printf(NA_FORMAT, "n/a*\n"); else { - printf(LABEL_FORMAT, msg); - fflush(stdout); - gettimeofday(&start_t, NULL); for (ops = 0; ops < ops_per_test; ops++) { @@ -433,7 +379,7 @@ test_open_sync(const char *msg, int writes_size) } #else - printf(NA_FORMAT, "open_sync", "n/a\n"); + printf(NA_FORMAT, "n/a\n"); #endif } diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index ec7e44315f..8e27f730a4 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2061,7 +2061,7 @@ SET ENABLE_SEQSCAN TO OFF; </varlistentry> <varlistentry id="guc-sync-standby-names" xreflabel="synchronous_standby_names"> - <term><varname>synchronous_standby_names</varname> (<type>integer</type>)</term> + <term><varname>synchronous_standby_names</varname> (<type>string</type>)</term> <indexterm> <primary><varname>synchronous_standby_names</> configuration parameter</primary> </indexterm> diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c5d75c4c65..4635cf2bb5 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -13269,7 +13269,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); <tbody> <row> - <entry><literal><function>format_type(<parameter>type_oid</parameter> [, <parameter>typemod</> [, <parameter>collation_oid</> ]])</function></literal></entry> + <entry><literal><function>format_type(<parameter>type_oid</parameter>, <parameter>typemod</>)</function></literal></entry> <entry><type>text</type></entry> <entry>get SQL name of a data type</entry> </row> @@ -13410,9 +13410,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); <para> <function>format_type</function> returns the SQL name of a data type that is identified by its type OID and possibly a type modifier. Pass NULL - for the type modifier or omit the argument if no specific modifier is known. - If a collation is given as third argument, a <literal>COLLATE</> clause - followed by a formatted collation name is appended. + for the type modifier if no specific modifier is known. </para> <para> @@ -13588,10 +13586,10 @@ SELECT typlen FROM pg_type WHERE oid = pg_typeof(33); </table> <para> - <function>col_description</function> returns the comment for a table column, - which is specified by the OID of its table and its column number. - <function>obj_description</function> cannot be used for table columns since - columns do not have OIDs of their own. + <function>col_description</function> returns the comment for a table + column, which is specified by the OID of its table and its column number. + (<function>obj_description</function> cannot be used for table columns + since columns do not have OIDs of their own.) </para> <para> @@ -13610,8 +13608,8 @@ SELECT typlen FROM pg_type WHERE oid = pg_typeof(33); <function>shobj_description</function> is used just like <function>obj_description</function> except it is used for retrieving comments on shared objects. Some system catalogs are global to all - databases within each cluster and their descriptions are stored globally - as well. + databases within each cluster, and the descriptions for objects in them + are stored globally as well. </para> <indexterm> @@ -14219,6 +14217,16 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); </tgroup> </table> + <indexterm> + <primary>pg_is_xlog_replay_paused</primary> + </indexterm> + <indexterm> + <primary>pg_xlog_replay_pause</primary> + </indexterm> + <indexterm> + <primary>pg_xlog_replay_resume</primary> + </indexterm> + <para> The functions shown in <xref linkend="functions-recovery-control-table"> control the progress of recovery. diff --git a/doc/src/sgml/pgupgrade.sgml b/doc/src/sgml/pgupgrade.sgml index 5b42fa85aa..c41068f074 100644 --- a/doc/src/sgml/pgupgrade.sgml +++ b/doc/src/sgml/pgupgrade.sgml @@ -58,13 +58,13 @@ <varlistentry> <term><option>-b</option> <replaceable>old_bindir</></term> - <term><option>--old-bindir</option> <replaceable>OLDBINDIR</></term> + <term><option>--old-bindir=</option><replaceable>OLDBINDIR</></term> <listitem><para>specify the old cluster executable directory</para></listitem> </varlistentry> <varlistentry> <term><option>-B</option> <replaceable>new_bindir</></term> - <term><option>--new-bindir</option> <replaceable>NEWBINDIR</></term> + <term><option>--new-bindir=</option><replaceable>NEWBINDIR</></term> <listitem><para>specify the new cluster executable directory</para></listitem> </varlistentry> @@ -76,13 +76,13 @@ <varlistentry> <term><option>-d</option> <replaceable>old_datadir</></term> - <term><option>--old-datadir</option> <replaceable>OLDDATADIR</></term> + <term><option>--old-datadir=</option><replaceable>OLDDATADIR</></term> <listitem><para>specify the old cluster data directory</para></listitem> </varlistentry> <varlistentry> <term><option>-D</option> <replaceable>new_datadir</></term> - <term><option>--new-datadir</option> <replaceable>NEWDATADIR</></term> + <term><option>--new-datadir=</option><replaceable>NEWDATADIR</></term> <listitem><para>specify the new cluster data directory</para></listitem> </varlistentry> @@ -94,7 +94,7 @@ <varlistentry> <term><option>-G</option> <replaceable>debug_filename</></term> - <term><option>--debugfile</option> <replaceable>DEBUGFILENAME</></term> + <term><option>--debugfile=</option><replaceable>DEBUGFILENAME</></term> <listitem><para>output debugging activity to file</para></listitem> </varlistentry> @@ -106,25 +106,25 @@ <varlistentry> <term><option>-l</option> <replaceable>log_filename</></term> - <term><option>--logfile</option> <replaceable>LOGFILENAME</></term> + <term><option>--logfile=</option><replaceable>LOGFILENAME</></term> <listitem><para>log session activity to file</para></listitem> </varlistentry> <varlistentry> <term><option>-p</option> <replaceable>old_portnum</></term> - <term><option>--old-port</option> <replaceable>portnum</></term> + <term><option>--old-port=</option><replaceable>portnum</></term> <listitem><para>specify the old cluster port number</para></listitem> </varlistentry> <varlistentry> <term><option>-P</option> <replaceable>new_portnum</></term> - <term><option>--new-port</option> <replaceable>portnum</></term> + <term><option>--new-port=</option><replaceable>portnum</></term> <listitem><para>specify the new cluster port number</para></listitem> </varlistentry> <varlistentry> <term><option>-u</option> <replaceable>username</></term> - <term><option>--user</option> <replaceable>username</></term> + <term><option>--user=</option><replaceable>username</></term> <listitem><para>clusters superuser</para></listitem> </varlistentry> diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index b8c4c507a2..c1948624d7 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -32,9 +32,9 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable> <phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase> - ADD [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ] + ADD [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ] DROP [ COLUMN ] [ IF EXISTS ] <replaceable class="PARAMETER">column</replaceable> [ RESTRICT | CASCADE ] - ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">type</replaceable> [ USING <replaceable class="PARAMETER">expression</replaceable> ] + ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ USING <replaceable class="PARAMETER">expression</replaceable> ] ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET DEFAULT <replaceable class="PARAMETER">expression</replaceable> ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> DROP DEFAULT ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | DROP } NOT NULL @@ -115,7 +115,11 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable> This form changes the type of a column of a table. Indexes and simple table constraints involving the column will be automatically converted to use the new column type by reparsing the originally - supplied expression. The optional <literal>USING</literal> + supplied expression. + The optional <literal>COLLATE</literal> clause specifies a collation + for the new column; if omitted, the collation is the default for the + new column type. + The optional <literal>USING</literal> clause specifies how to compute the new column value from the old; if omitted, the default conversion is the same as an assignment cast from old data type to new. A <literal>USING</literal> diff --git a/doc/src/sgml/ref/alter_type.sgml b/doc/src/sgml/ref/alter_type.sgml index 09db0cc8b2..e889ffbc35 100644 --- a/doc/src/sgml/ref/alter_type.sgml +++ b/doc/src/sgml/ref/alter_type.sgml @@ -32,9 +32,9 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea <phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase> - ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ] + ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ CASCADE | RESTRICT ] DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable> [ CASCADE | RESTRICT ] - ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ] + ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> diff --git a/doc/src/sgml/ref/clusterdb.sgml b/doc/src/sgml/ref/clusterdb.sgml index 5ce3a41fc7..081f398706 100644 --- a/doc/src/sgml/ref/clusterdb.sgml +++ b/doc/src/sgml/ref/clusterdb.sgml @@ -77,7 +77,7 @@ PostgreSQL documentation <varlistentry> <term><option><optional>-d</> <replaceable class="parameter">dbname</replaceable></></term> - <term><option><optional>--dbname</> <replaceable class="parameter">dbname</replaceable></></term> + <term><option><optional>--dbname=</><replaceable class="parameter">dbname</replaceable></></term> <listitem> <para> Specifies the name of the database to be clustered. @@ -113,7 +113,7 @@ PostgreSQL documentation <varlistentry> <term><option>-t <replaceable class="parameter">table</replaceable></></term> - <term><option>--table <replaceable class="parameter">table</replaceable></></term> + <term><option>--table=<replaceable class="parameter">table</replaceable></></term> <listitem> <para> Cluster <replaceable class="parameter">table</replaceable> only. @@ -162,7 +162,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the server is @@ -174,7 +174,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or local Unix domain socket file @@ -186,7 +186,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as. diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml index 2610fd5b8d..bc848b3069 100644 --- a/doc/src/sgml/ref/comment.sgml +++ b/doc/src/sgml/ref/comment.sgml @@ -65,11 +65,18 @@ COMMENT ON </para> <para> - To modify a comment, issue a new <command>COMMENT</> command for the - same object. Only one comment string is stored for each object. - To remove a comment, write <literal>NULL</literal> in place of the text - string. - Comments are automatically dropped when the object is dropped. + Only one comment string is stored for each object, so to modify a comment, + issue a new <command>COMMENT</> command for the same object. To remove a + comment, write <literal>NULL</literal> in place of the text string. + Comments are automatically dropped when their object is dropped. + </para> + + <para> + For most kinds of object, only the object's owner can set the comment. + Roles don't have owners, so the rule for <literal>COMMENT ON ROLE</> is + that you must be superuser to comment on a superuser role, or have the + <literal>CREATEROLE</> privilege to comment on non-superuser roles. + Of course, a superuser can comment on anything. </para> <para> @@ -93,15 +100,15 @@ COMMENT ON <term><replaceable class="parameter">agg_name</replaceable></term> <term><replaceable class="parameter">constraint_name</replaceable></term> <term><replaceable class="parameter">function_name</replaceable></term> - <term><replaceable class="parameter">op</replaceable></term> + <term><replaceable class="parameter">operator_name</replaceable></term> <term><replaceable class="parameter">rule_name</replaceable></term> <term><replaceable class="parameter">trigger_name</replaceable></term> <listitem> <para> The name of the object to be commented. Names of tables, - aggregates, domains, foreign tables, functions, indexes, operators, - operator classes, operator families, sequences, text search objects, - types, and views can be schema-qualified. + aggregates, collations, conversions, domains, foreign tables, functions, + indexes, operators, operator classes, operator families, sequences, + text search objects, types, and views can be schema-qualified. </para> </listitem> </varlistentry> @@ -137,7 +144,6 @@ COMMENT ON <varlistentry> <term><replaceable class="parameter">argmode</replaceable></term> - <listitem> <para> The mode of a function argument: <literal>IN</>, <literal>OUT</>, @@ -154,7 +160,6 @@ COMMENT ON <varlistentry> <term><replaceable class="parameter">argname</replaceable></term> - <listitem> <para> The name of a function argument. @@ -167,7 +172,6 @@ COMMENT ON <varlistentry> <term><replaceable class="parameter">argtype</replaceable></term> - <listitem> <para> The data type(s) of the function's arguments (optionally @@ -185,9 +189,20 @@ COMMENT ON </listitem> </varlistentry> + <varlistentry> + <term><replaceable class="parameter">left_type</replaceable></term> + <term><replaceable class="parameter">right_type</replaceable></term> + <listitem> + <para> + The data type(s) of the operator's arguments (optionally + schema-qualified). Write <literal>NONE</> for the missing argument + of a prefix or postfix operator. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>PROCEDURAL</literal></term> - <listitem> <para> This is a noise word. @@ -212,12 +227,11 @@ COMMENT ON <title>Notes</title> <para> - There is presently no security mechanism for comments: any user + There is presently no security mechanism for viewing comments: any user connected to a database can see all the comments for objects in - that database (although only superusers can change comments for - objects that they don't own). For shared objects such as - databases, roles, and tablespaces comments are stored globally - and any user connected to any database can see all the comments + that database. For shared objects such as + databases, roles, and tablespaces, comments are stored globally so any + user connected to any database in the cluster can see all the comments for shared objects. Therefore, don't put security-critical information in comments. </para> @@ -257,7 +271,7 @@ COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee ID'; COMMENT ON LANGUAGE plpython IS 'Python support for stored procedures'; COMMENT ON LARGE OBJECT 346344 IS 'Planning document'; COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two texts'; -COMMENT ON OPERATOR - (NONE, text) IS 'This is a prefix operator on text'; +COMMENT ON OPERATOR - (NONE, integer) IS 'Unary minus'; COMMENT ON OPERATOR CLASS int4ops USING btree IS '4 byte integer operators for btrees'; COMMENT ON OPERATOR FAMILY integer_ops USING btree IS 'all integer operators for btrees'; COMMENT ON ROLE my_role IS 'Administration group for finance tables'; diff --git a/doc/src/sgml/ref/create_domain.sgml b/doc/src/sgml/ref/create_domain.sgml index 83be889c6d..2300edefe3 100644 --- a/doc/src/sgml/ref/create_domain.sgml +++ b/doc/src/sgml/ref/create_domain.sgml @@ -89,8 +89,9 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea <listitem> <para> An optional collation for the domain. If no collation is - specified, the database default collation is used (which can - be overridden when the domain is used to define a column). + specified, the underlying data type's default collation is used. + The underlying type must be collatable when <literal>COLLATE</> + is specified. </para> </listitem> </varlistentry> diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 9d2d99ad2e..0fbe116097 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -248,9 +248,9 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI <term><literal>COLLATE <replaceable>collation</replaceable></literal></term> <listitem> <para> - The <literal>COLLATE</> clause assigns a nondefault collation to - the column. By default, the locale settings of the database are - used. + The <literal>COLLATE</> clause assigns a collation to + the column (which must be of a collatable data type). + If not specified, the column data type's default collation is used. </para> </listitem> </varlistentry> diff --git a/doc/src/sgml/ref/createdb.sgml b/doc/src/sgml/ref/createdb.sgml index 633881d6f7..7cbf56506d 100644 --- a/doc/src/sgml/ref/createdb.sgml +++ b/doc/src/sgml/ref/createdb.sgml @@ -87,7 +87,7 @@ PostgreSQL documentation <varlistentry> <term><option>-D <replaceable class="parameter">tablespace</replaceable></></term> - <term><option>--tablespace <replaceable class="parameter">tablespace</replaceable></></term> + <term><option>--tablespace=<replaceable class="parameter">tablespace</replaceable></></term> <listitem> <para> Specifies the default tablespace for the database. @@ -108,7 +108,7 @@ PostgreSQL documentation <varlistentry> <term><option>-l <replaceable class="parameter">locale</replaceable></></term> - <term><option>--locale <replaceable class="parameter">locale</replaceable></></term> + <term><option>--locale=<replaceable class="parameter">locale</replaceable></></term> <listitem> <para> Specifies the locale to be used in this database. This is equivalent @@ -118,7 +118,7 @@ PostgreSQL documentation </varlistentry> <varlistentry> - <term><option>--lc-collate <replaceable class="parameter">locale</replaceable></></term> + <term><option>--lc-collate=<replaceable class="parameter">locale</replaceable></></term> <listitem> <para> Specifies the LC_COLLATE setting to be used in this database. @@ -127,7 +127,7 @@ PostgreSQL documentation </varlistentry> <varlistentry> - <term><option>--lc-ctype <replaceable class="parameter">locale</replaceable></></term> + <term><option>--lc-ctype=<replaceable class="parameter">locale</replaceable></></term> <listitem> <para> Specifies the LC_CTYPE setting to be used in this database. @@ -137,7 +137,7 @@ PostgreSQL documentation <varlistentry> <term><option>-E <replaceable class="parameter">encoding</replaceable></></term> - <term><option>--encoding <replaceable class="parameter">encoding</replaceable></></term> + <term><option>--encoding=<replaceable class="parameter">encoding</replaceable></></term> <listitem> <para> Specifies the character encoding scheme to be used in this @@ -150,7 +150,7 @@ PostgreSQL documentation <varlistentry> <term><option>-O <replaceable class="parameter">owner</replaceable></></term> - <term><option>--owner <replaceable class="parameter">owner</replaceable></></term> + <term><option>--owner=<replaceable class="parameter">owner</replaceable></></term> <listitem> <para> Specifies the database user who will own the new database. @@ -160,7 +160,7 @@ PostgreSQL documentation <varlistentry> <term><option>-T <replaceable class="parameter">template</replaceable></></term> - <term><option>--template <replaceable class="parameter">template</replaceable></></term> + <term><option>--template=<replaceable class="parameter">template</replaceable></></term> <listitem> <para> Specifies the template database from which to build this database. @@ -207,7 +207,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the @@ -219,7 +219,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or the local Unix domain socket file @@ -230,7 +230,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as. diff --git a/doc/src/sgml/ref/createlang.sgml b/doc/src/sgml/ref/createlang.sgml index 0bc1976c15..f01f298322 100644 --- a/doc/src/sgml/ref/createlang.sgml +++ b/doc/src/sgml/ref/createlang.sgml @@ -77,7 +77,7 @@ PostgreSQL documentation <varlistentry> <term><option><optional>-d</> <replaceable class="parameter">dbname</replaceable></></term> - <term><option><optional>--dbname</> <replaceable class="parameter">dbname</replaceable></></term> + <term><option><optional>--dbname=</><replaceable class="parameter">dbname</replaceable></></term> <listitem> <para> Specifies the database to which the language should be added. @@ -138,7 +138,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the @@ -151,7 +151,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or local Unix domain socket file @@ -163,7 +163,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as. diff --git a/doc/src/sgml/ref/createuser.sgml b/doc/src/sgml/ref/createuser.sgml index fbc184f4c8..0c47fb4997 100644 --- a/doc/src/sgml/ref/createuser.sgml +++ b/doc/src/sgml/ref/createuser.sgml @@ -78,7 +78,7 @@ PostgreSQL documentation <varlistentry> <term><option>-c <replaceable class="parameter">number</replaceable></></term> - <term><option>--connection-limit <replaceable class="parameter">number</replaceable></></term> + <term><option>--connection-limit=<replaceable class="parameter">number</replaceable></></term> <listitem> <para> Set a maximum number of connections for the new user. @@ -276,7 +276,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the @@ -289,7 +289,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or local Unix domain socket file @@ -301,7 +301,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as (not the user name to create). diff --git a/doc/src/sgml/ref/dropdb.sgml b/doc/src/sgml/ref/dropdb.sgml index c169d7fcd4..1aa76cdb57 100644 --- a/doc/src/sgml/ref/dropdb.sgml +++ b/doc/src/sgml/ref/dropdb.sgml @@ -118,7 +118,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the @@ -131,7 +131,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or local Unix domain socket file @@ -143,7 +143,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as. diff --git a/doc/src/sgml/ref/droplang.sgml b/doc/src/sgml/ref/droplang.sgml index 810c78e521..0ad640b0b4 100644 --- a/doc/src/sgml/ref/droplang.sgml +++ b/doc/src/sgml/ref/droplang.sgml @@ -79,7 +79,7 @@ PostgreSQL documentation <varlistentry> <term><option><optional>-d</> <replaceable class="parameter">dbname</replaceable></></term> - <term><option><optional>--dbname</> <replaceable class="parameter">dbname</replaceable></></term> + <term><option><optional>--dbname=</><replaceable class="parameter">dbname</replaceable></></term> <listitem> <para> Specifies from which database the language should be removed. @@ -140,7 +140,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the @@ -153,7 +153,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the Internet TCP/IP port or local Unix domain socket file @@ -165,7 +165,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as. diff --git a/doc/src/sgml/ref/dropuser.sgml b/doc/src/sgml/ref/dropuser.sgml index 0786612820..3089a21954 100644 --- a/doc/src/sgml/ref/dropuser.sgml +++ b/doc/src/sgml/ref/dropuser.sgml @@ -119,7 +119,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the @@ -132,7 +132,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or local Unix domain socket file @@ -144,7 +144,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as (not the user name to drop). diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index 04f047b063..d816c21c08 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -22,9 +22,9 @@ PostgreSQL documentation <refsynopsisdiv> <cmdsynopsis> <command>initdb</command> - <arg rep="repeat"><replaceable>option</></arg> + <arg rep="repeat"><replaceable>option</replaceable></arg> <group choice="plain"> - <arg>--pgdata </arg> + <arg>--pgdata</arg> <arg>-D </arg> <replaceable>directory</replaceable> </group> @@ -186,16 +186,14 @@ PostgreSQL documentation </varlistentry> <varlistentry> - <term><option>-X <replaceable class="parameter">directory</replaceable></option></term> - <term><option>--xlogdir=<replaceable class="parameter">directory</replaceable></option></term> + <term><option>--pwfile=<replaceable>filename</></option></term> <listitem> <para> - This option specifies the directory where the transaction log - should be stored. + Makes <command>initdb</command> read the database superuser's password + from a file. The first line of the file is taken as the password. </para> </listitem> </varlistentry> - <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></option></term> <term><option>--username=<replaceable class="parameter">username</replaceable></option></term> @@ -226,14 +224,16 @@ PostgreSQL documentation </varlistentry> <varlistentry> - <term><option>--pwfile=<replaceable>filename</></option></term> + <term><option>-X <replaceable class="parameter">directory</replaceable></option></term> + <term><option>--xlogdir=<replaceable class="parameter">directory</replaceable></option></term> <listitem> <para> - Makes <command>initdb</command> read the database superuser's password - from a file. The first line of the file is taken as the password. + This option specifies the directory where the transaction log + should be stored. </para> </listitem> </varlistentry> + </variablelist> </para> diff --git a/doc/src/sgml/ref/pg_controldata.sgml b/doc/src/sgml/ref/pg_controldata.sgml index 50b1909499..d39b6e18f8 100644 --- a/doc/src/sgml/ref/pg_controldata.sgml +++ b/doc/src/sgml/ref/pg_controldata.sgml @@ -22,6 +22,7 @@ PostgreSQL documentation <refsynopsisdiv> <cmdsynopsis> <command>pg_controldata</command> + <arg><replaceable class="parameter">option</replaceable></arg> <arg><replaceable class="parameter">datadir</replaceable></arg> </cmdsynopsis> </refsynopsisdiv> diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml index 307f66b8da..608749f4c6 100644 --- a/doc/src/sgml/ref/pg_ctl-ref.sgml +++ b/doc/src/sgml/ref/pg_ctl-ref.sgml @@ -499,22 +499,22 @@ PostgreSQL documentation <title>Starting the Server</title> <para> - To start up a server: + To start the server: <screen> <prompt>$</prompt> <userinput>pg_ctl start</userinput> </screen> </para> <para> - An example of starting the server, and waiting until the server is - accepting connection: + To start the server, waiting until the server is + accepting connections: <screen> <prompt>$</prompt> <userinput>pg_ctl -w start</userinput> </screen> </para> <para> - For a server using port 5433, and + To start the server using port 5433, and running without <function>fsync</function>, use: <screen> <prompt>$</prompt> <userinput>pg_ctl -o "-F -p 5433" start</userinput> @@ -530,7 +530,10 @@ PostgreSQL documentation <prompt>$</prompt> <userinput>pg_ctl stop</userinput> </screen> The <option>-m</option> option allows control over - <emphasis>how</emphasis> the server shuts down. + <emphasis>how</emphasis> the server shuts down: +<screen> +<prompt>$</prompt> <userinput>pg_ctl stop -m fast</userinput> +</screen> </para> </refsect2> @@ -557,7 +560,7 @@ PostgreSQL documentation </para> <para> - To restart using port 5433 and disable <function>fsync</> upon restart: + To restart using port 5433, disabling <function>fsync</> upon restart: <screen> <prompt>$</prompt> <userinput>pg_ctl -o "-F -p 5433" restart</userinput> </screen> diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index 25dc2a7014..e78d275c0d 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -301,7 +301,8 @@ PostgreSQL documentation linkend="APP-PSQL-patterns" endterm="APP-PSQL-patterns-title">), so multiple schemas can also be selected by writing wildcard characters in the pattern. When using wildcards, be careful to quote the pattern - if needed to prevent the shell from expanding the wildcards. + if needed to prevent the shell from expanding the wildcards; see + <xref linkend="pg-dump-examples" endterm="pg-dump-examples-title">. </para> <note> @@ -435,7 +436,8 @@ PostgreSQL documentation linkend="APP-PSQL-patterns" endterm="APP-PSQL-patterns-title">), so multiple tables can also be selected by writing wildcard characters in the pattern. When using wildcards, be careful to quote the pattern - if needed to prevent the shell from expanding the wildcards. + if needed to prevent the shell from expanding the wildcards; see + <xref linkend="pg-dump-examples" endterm="pg-dump-examples-title">. </para> <para> @@ -973,7 +975,7 @@ CREATE DATABASE foo WITH TEMPLATE template0; </refsect1> <refsect1 id="pg-dump-examples"> - <title>Examples</title> + <title id="pg-dump-examples-title">Examples</title> <para> To dump a database called <literal>mydb</> into a SQL-script file: diff --git a/doc/src/sgml/ref/postgres-ref.sgml b/doc/src/sgml/ref/postgres-ref.sgml index 4437bf8997..bd4ae338f7 100644 --- a/doc/src/sgml/ref/postgres-ref.sgml +++ b/doc/src/sgml/ref/postgres-ref.sgml @@ -66,9 +66,9 @@ PostgreSQL documentation The <command>postgres</command> command can also be called in single-user mode. The primary use for this mode is during bootstrapping by <xref linkend="app-initdb">. Sometimes it is used - for debugging or disaster recovery (but note that running a single-user + for debugging or disaster recovery; note that running a single-user server is not truly suitable for debugging the server, since no - realistic interprocess communication and locking will happen). + realistic interprocess communication and locking will happen. When invoked in single-user mode from the shell, the user can enter queries and the results will be printed to the screen, but in a form that is more useful @@ -413,8 +413,8 @@ PostgreSQL documentation <term><option>-P</option></term> <listitem> <para> - Ignore system indexes when reading system tables (but still update - the indexes when modifying the tables). This is useful when + Ignore system indexes when reading system tables, but still update + the indexes when modifying the tables. This is useful when recovering from damaged system indexes. </para> </listitem> @@ -745,7 +745,10 @@ PostgreSQL documentation <para> Note that the single-user mode server does not provide sophisticated - line-editing features (no command history, for example). + line-editing features (no command history, for example). + Single-User mode also does not do any background processing, like + automatic checkpoints. + </para> </refsect1> @@ -763,13 +766,11 @@ PostgreSQL documentation <para> To start <command>postgres</command> with a specific - port: + port, e.g. 1234: <screen> <prompt>$</prompt> <userinput>postgres -p 1234</userinput> </screen> - This command will start up <command>postgres</command> - communicating through the port 1234. In order to connect to this - server using <application>psql</>, you would need to run it as + To connect to this server using <application>psql</>, specify this port with the -p option: <screen> <prompt>$</prompt> <userinput>psql -p 1234</userinput> </screen> diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index baefb57882..24e8ee0a36 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -74,7 +74,7 @@ PostgreSQL documentation <varlistentry> <term><option>-c <replaceable class="parameter">command</replaceable></></term> - <term><option>--command <replaceable class="parameter">command</replaceable></></term> + <term><option>--command=<replaceable class="parameter">command</replaceable></></term> <listitem> <para> Specifies that <application>psql</application> is to execute one @@ -107,7 +107,7 @@ PostgreSQL documentation <varlistentry> <term><option>-d <replaceable class="parameter">dbname</replaceable></></term> - <term><option>--dbname <replaceable class="parameter">dbname</replaceable></></term> + <term><option>--dbname=<replaceable class="parameter">dbname</replaceable></></term> <listitem> <para> Specifies the name of the database to connect to. This is @@ -151,7 +151,7 @@ PostgreSQL documentation <varlistentry> <term><option>-f <replaceable class="parameter">filename</replaceable></></term> - <term><option>--file <replaceable class="parameter">filename</replaceable></></term> + <term><option>--file=<replaceable class="parameter">filename</replaceable></></term> <listitem> <para> Use the file <replaceable class="parameter">filename</replaceable> @@ -183,7 +183,7 @@ PostgreSQL documentation <varlistentry> <term><option>-F <replaceable class="parameter">separator</replaceable></></term> - <term><option>--field-separator <replaceable class="parameter">separator</replaceable></></term> + <term><option>--field-separator=<replaceable class="parameter">separator</replaceable></></term> <listitem> <para> Use <replaceable class="parameter">separator</replaceable> as the @@ -195,7 +195,7 @@ PostgreSQL documentation <varlistentry> <term><option>-h <replaceable class="parameter">hostname</replaceable></></term> - <term><option>--host <replaceable class="parameter">hostname</replaceable></></term> + <term><option>--host=<replaceable class="parameter">hostname</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the @@ -232,7 +232,7 @@ PostgreSQL documentation <varlistentry> <term><option>-L <replaceable class="parameter">filename</replaceable></></term> - <term><option>--log-file <replaceable class="parameter">filename</replaceable></></term> + <term><option>--log-file=<replaceable class="parameter">filename</replaceable></></term> <listitem> <para> Write all query output into file <replaceable @@ -255,7 +255,7 @@ PostgreSQL documentation <varlistentry> <term><option>-o <replaceable class="parameter">filename</replaceable></></term> - <term><option>--output <replaceable class="parameter">filename</replaceable></></term> + <term><option>--output=<replaceable class="parameter">filename</replaceable></></term> <listitem> <para> Put all query output into file <replaceable @@ -267,7 +267,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or the local Unix-domain @@ -281,7 +281,7 @@ PostgreSQL documentation <varlistentry> <term><option>-P <replaceable class="parameter">assignment</replaceable></></term> - <term><option>--pset <replaceable class="parameter">assignment</replaceable></></term> + <term><option>--pset=<replaceable class="parameter">assignment</replaceable></></term> <listitem> <para> Specifies printing options, in the style of @@ -310,7 +310,7 @@ PostgreSQL documentation <varlistentry> <term><option>-R <replaceable class="parameter">separator</replaceable></></term> - <term><option>--record-separator <replaceable class="parameter">separator</replaceable></></term> + <term><option>--record-separator=<replaceable class="parameter">separator</replaceable></></term> <listitem> <para> Use <replaceable class="parameter">separator</replaceable> as the @@ -365,7 +365,7 @@ PostgreSQL documentation <varlistentry> <term><option>-T <replaceable class="parameter">table_options</replaceable></></term> - <term><option>--table-attr <replaceable class="parameter">table_options</replaceable></></term> + <term><option>--table-attr=<replaceable class="parameter">table_options</replaceable></></term> <listitem> <para> Specifies options to be placed within the @@ -377,7 +377,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> Connect to the database as the user <replaceable @@ -389,8 +389,8 @@ PostgreSQL documentation <varlistentry> <term><option>-v <replaceable class="parameter">assignment</replaceable></></term> - <term><option>--set <replaceable class="parameter">assignment</replaceable></></term> - <term><option>--variable <replaceable class="parameter">assignment</replaceable></></term> + <term><option>--set=<replaceable class="parameter">assignment</replaceable></></term> + <term><option>--variable=<replaceable class="parameter">assignment</replaceable></></term> <listitem> <para> Perform a variable assignment, like the <command>\set</command> diff --git a/doc/src/sgml/ref/reindexdb.sgml b/doc/src/sgml/ref/reindexdb.sgml index fa4d7b41c7..026bdcc718 100644 --- a/doc/src/sgml/ref/reindexdb.sgml +++ b/doc/src/sgml/ref/reindexdb.sgml @@ -80,7 +80,7 @@ PostgreSQL documentation <varlistentry> <term><option><optional>-d</> <replaceable class="parameter">dbname</replaceable></></term> - <term><option><optional>--dbname</> <replaceable class="parameter">dbname</replaceable></></term> + <term><option><optional>--dbname=</><replaceable class="parameter">dbname</replaceable></></term> <listitem> <para> Specifies the name of the database to be reindexed. @@ -106,7 +106,7 @@ PostgreSQL documentation <varlistentry> <term><option>-i <replaceable class="parameter">index</replaceable></></term> - <term><option>--index <replaceable class="parameter">index</replaceable></></term> + <term><option>--index=<replaceable class="parameter">index</replaceable></></term> <listitem> <para> Recreate <replaceable class="parameter">index</replaceable> only. @@ -136,7 +136,7 @@ PostgreSQL documentation <varlistentry> <term><option>-t <replaceable class="parameter">table</replaceable></></term> - <term><option>--table <replaceable class="parameter">table</replaceable></></term> + <term><option>--table=<replaceable class="parameter">table</replaceable></></term> <listitem> <para> Reindex <replaceable class="parameter">table</replaceable> only. @@ -176,7 +176,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the server is @@ -188,7 +188,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or local Unix domain socket file @@ -200,7 +200,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as. diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml index b4833f1252..e9022fe947 100644 --- a/doc/src/sgml/ref/vacuumdb.sgml +++ b/doc/src/sgml/ref/vacuumdb.sgml @@ -85,7 +85,7 @@ PostgreSQL documentation <varlistentry> <term><option><optional>-d</> <replaceable class="parameter">dbname</replaceable></option></term> - <term><option><optional>--dbname</> <replaceable class="parameter">dbname</replaceable></option></term> + <term><option><optional>--dbname=</><replaceable class="parameter">dbname</replaceable></option></term> <listitem> <para> Specifies the name of the database to be cleaned or analyzed. @@ -141,7 +141,7 @@ PostgreSQL documentation <varlistentry> <term><option>-t <replaceable class="parameter">table</replaceable> [ (<replaceable class="parameter">column</replaceable> [,...]) ]</option></term> - <term><option>--table <replaceable class="parameter">table</replaceable> [ (<replaceable class="parameter">column</replaceable> [,...]) ]</option></term> + <term><option>--table=<replaceable class="parameter">table</replaceable> [ (<replaceable class="parameter">column</replaceable> [,...]) ]</option></term> <listitem> <para> Clean or analyze <replaceable class="parameter">table</replaceable> only. @@ -217,7 +217,7 @@ PostgreSQL documentation <variablelist> <varlistentry> <term><option>-h <replaceable class="parameter">host</replaceable></></term> - <term><option>--host <replaceable class="parameter">host</replaceable></></term> + <term><option>--host=<replaceable class="parameter">host</replaceable></></term> <listitem> <para> Specifies the host name of the machine on which the server @@ -229,7 +229,7 @@ PostgreSQL documentation <varlistentry> <term><option>-p <replaceable class="parameter">port</replaceable></></term> - <term><option>--port <replaceable class="parameter">port</replaceable></></term> + <term><option>--port=<replaceable class="parameter">port</replaceable></></term> <listitem> <para> Specifies the TCP port or local Unix domain socket file @@ -241,7 +241,7 @@ PostgreSQL documentation <varlistentry> <term><option>-U <replaceable class="parameter">username</replaceable></></term> - <term><option>--username <replaceable class="parameter">username</replaceable></></term> + <term><option>--username=<replaceable class="parameter">username</replaceable></></term> <listitem> <para> User name to connect as. diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml index 2ea0fd7e21..9f14a46f7c 100644 --- a/doc/src/sgml/release-9.1.sgml +++ b/doc/src/sgml/release-9.1.sgml @@ -1,6 +1,6 @@ <!-- doc/src/sgml/release-9.1.sgml --> -<!-- This is (hopefully) up-to-date with commits through 2011-03-05 --> +<!-- This is (hopefully) up-to-date with commits through 2011-03-08 --> <sect1 id="release-9-1-alpha"> <title>Release 9.1alpha4</title> @@ -122,6 +122,24 @@ </para> </listitem> + <listitem> + <para> + <emphasis>Synchronous replication</emphasis> + </para> + <para> + When enabled, transaction commit will wait for WAL records to be + replicated before informing the client that a transaction has + successfully committed. + </para> + </listitem> + + <listitem> + <para> + <emphasis>When recovery_target_timeline='latest', periodically + rescan the archive for new timelines</emphasis> + </para> + </listitem> + </itemizedlist> </sect3> @@ -226,7 +244,7 @@ <listitem> <para> <emphasis>Allow a table's row type to be cast to the table's supertype - if it's a type table.</emphasis> + if it's a type table</emphasis> </para> <para> This is analagous to the existing facility that allows casting a row @@ -237,7 +255,7 @@ <listitem> <para> <emphasis>Make foreign data wrappers functional, and support FOREIGN - TABLEs.</emphasis> + TABLEs</emphasis> </para> <para> Foreign tables are component of SQL/MED, and provide a framework to @@ -249,14 +267,14 @@ <listitem> <para> <emphasis>Allow a unique or primary key constraint to be created - using an existing index.</emphasis> + using an existing index</emphasis> </para> </listitem> <listitem> <para> <emphasis>Implement Serializable Snapshot Isolation, in order to - provide a more robust serializable transaction mode.</emphasis> + provide a more robust serializable transaction mode</emphasis> </para> <para> In previous releases, the REPEATABLE READ and SERIALIZABLE isolation @@ -290,7 +308,7 @@ <listitem> <para> - <emphasis>Teach ALTER TABLE .. SET DATA TYPE to avoid a table write + <emphasis>Teach ALTER TABLE ... SET DATA TYPE to avoid a table write in some cases where it isn't necessary </emphasis> </para> @@ -372,7 +390,7 @@ <listitem> <para> - <emphasis>Support unlogged tables.</emphasis> + <emphasis>Support unlogged tables</emphasis> </para> <para> The contents of an unlogged table are not WAL-logged; thus, they @@ -384,7 +402,7 @@ <listitem> <para> - <emphasis>Hash joins now support right and full outer joins.</emphasis> + <emphasis>Hash joins now support right and full outer joins</emphasis> </para> <para> Previously, full joins could be implemented only as a merge join, @@ -581,8 +599,7 @@ <listitem> <para> - Support host names and host key - word <literal>all</literal> + Support host names and host key word <literal>all</literal> in <filename>pg_hba.conf</filename> </para> </listitem> @@ -648,7 +665,7 @@ <para> <emphasis>When an autovacuum worker (other than one performing an anti-wraparound vacuum) is unable to obtain a lock on the target - relation without blocking, skip the relation.</emphasis> + relation without blocking, skip the relation</emphasis> </para> <para> This avoids pinning down an autovacuum worker. The next autovacuum @@ -694,7 +711,7 @@ <listitem> <para> - <emphasis>Add REPLICATION privilege for ROLEs.</emphasis> + <emphasis>Add REPLICATION privilege for ROLEs</emphasis> </para> <para> This makes it possible for replication to be performed by a @@ -781,7 +798,7 @@ <listitem> <para> <emphasis>Change pg_last_xlog_receive_location not to move - backwards.</emphasis> + backwards</emphasis> </para> </listitem> @@ -1011,15 +1028,14 @@ <listitem> <para> - <emphasis>Skip dropped attributes when converting Python objects to - tuples</emphasis> + <emphasis>Make plpy.Fatal() raise FATAL, rather than ERROR</emphasis> </para> </listitem> <listitem> <para> - <emphasis>Improve messages for errors in compiling anonymous - PL/Python blocks</emphasis> + <emphasis>Skip dropped attributes when converting Python objects to + tuples</emphasis> </para> </listitem> @@ -1043,11 +1059,17 @@ <listitem> <para> - <emphasis>Do not prefix error messages with the string - "PL/Python: "</emphasis> + <emphasis>Improve error reporting</emphasis> </para> - <para> - It is redundant, given the error context. + <para>Better error messages for errors in compiling anonymous + PL/Python blocks. Avoid prefixing error messages with the string + "PL/Python: ", which is redundant, given the error + context. Provide a separate exception class for each error code + the backend defines, and make it possible to get the SQLSTATE from + the exception object. Report Python errors from iterators + using PLy_elog, so that the Python exception is included in the + exception, and to avoid setting the errcode to + ERRCODE_DATA_EXCEPTION. </para> </listitem> @@ -1097,14 +1119,6 @@ <listitem> <para> - <emphasis>Provide a separate exception class for each error code - the backend defines, and make it possible to get the SQLSTATE from - the exception object</emphasis> - </para> - </listitem> - - <listitem> - <para> <emphasis>Assorted code cleanup</emphasis> </para> <para> diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml index b4c4b5e23e..4822394300 100644 --- a/doc/src/sgml/syntax.sgml +++ b/doc/src/sgml/syntax.sgml @@ -1259,6 +1259,12 @@ SELECT 3 OPERATOR(pg_catalog.+) 4; <listitem> <para> + A collation expression + </para> + </listitem> + + <listitem> + <para> A scalar subquery </para> </listitem> @@ -1898,8 +1904,8 @@ CAST ( <replaceable>expression</replaceable> AS <replaceable>type</replaceable> </note> </sect2> - <sect2 id="sql-syntax-collate-clause"> - <title>COLLATE Clause</title> + <sect2 id="sql-syntax-collate-exprs"> + <title>Collation Expressions</title> <indexterm> <primary>COLLATE</primary> @@ -1925,7 +1931,7 @@ CAST ( <replaceable>expression</replaceable> AS <replaceable>type</replaceable> </para> <para> - The two typical uses of the <literal>COLLATE</literal> clause are + The two common uses of the <literal>COLLATE</literal> clause are overriding the sort order in an <literal>ORDER BY</> clause, for example: <programlisting> @@ -1934,15 +1940,28 @@ SELECT a, b, c FROM tbl WHERE ... ORDER BY a COLLATE "C"; and overriding the collation of a function or operator call that has locale-sensitive results, for example: <programlisting> -SELECT * FROM tbl WHERE a > 'foo' COLLATE "C"; +SELECT * FROM tbl WHERE a > 'foo' COLLATE "C"; +</programlisting> + Note that in the latter case the <literal>COLLATE</> clause is + attached to an input argument of the operator we wish to affect. + It doesn't matter which argument of the operator or function call the + <literal>COLLATE</> clause is attached to, because the collation that is + applied by the operator or function is derived by considering all + arguments, and an explicit <literal>COLLATE</> clause will override the + collations of all other arguments. (Attaching non-matching + <literal>COLLATE</> clauses to more than one argument, however, is an + error. For more details see <xref linkend="collation">.) + Thus, this gives the same result as the previous example: +<programlisting> +SELECT * FROM tbl WHERE a COLLATE "C" > 'foo'; +</programlisting> + But this is an error: +<programlisting> +SELECT * FROM tbl WHERE (a > 'foo') COLLATE "C"; </programlisting> - In the latter case it doesn't matter which argument of the - operator of function call the <literal>COLLATE</> clause is - attached to, because the collation that is applied by the operator - or function is derived from all arguments, and - the <literal>COLLATE</> clause will override the collations of all - other arguments. Attaching nonmatching <literal>COLLATE</> - clauses to more than one argument, however, is an error. + because it attempts to apply a collation to the result of the + <literal>></> operator, which is of the non-collatable data type + <type>boolean</>. </para> </sect2> diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index c65f8522b3..1a35014170 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -116,9 +116,9 @@ Besides <command>SELECT</command> queries, the commands can include data modification queries (<command>INSERT</command>, <command>UPDATE</command>, and <command>DELETE</command>), as well as - other SQL commands. (The only exception is that you cannot put - <command>BEGIN</>, <command>COMMIT</>, <command>ROLLBACK</>, or - <command>SAVEPOINT</> commands into a <acronym>SQL</acronym> function.) + other SQL commands. (You cannot use transaction control commands, e.g. + <command>COMMIT</>, <command>SAVEPOINT</>, and some utility + commands, e.g. <literal>VACUUM</>, in <acronym>SQL</acronym> functions.) However, the final command must be a <command>SELECT</command> or have a <literal>RETURNING</> clause that returns whatever is diff --git a/src/Makefile b/src/Makefile index 4469d2cdf2..a0460342e8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -50,14 +50,19 @@ uninstall: uninstall-local uninstall-local: rm -f $(addprefix '$(DESTDIR)$(pgxsdir)/$(subdir)'/, Makefile.global Makefile.port Makefile.shlib nls-global.mk) +distprep: + $(MAKE) -C test/isolation $@ + clean: $(MAKE) -C test $@ $(MAKE) -C tutorial NO_PGXS=1 $@ + $(MAKE) -C test/isolation $@ $(MAKE) -C test/thread $@ distclean maintainer-clean: $(MAKE) -C test $@ $(MAKE) -C tutorial NO_PGXS=1 $@ + $(MAKE) -C test/isolation $@ $(MAKE) -C test/thread $@ rm -f Makefile.port Makefile.global diff --git a/src/backend/Makefile b/src/backend/Makefile index 2b2c9bb9a2..bbc59f76c7 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -193,10 +193,12 @@ utils/probes.o: utils/probes.d $(SUBDIROBJS) ########################################################################## +# Be sure that these files get removed by the maintainer-clean target distprep: $(MAKE) -C parser gram.c gram.h scan.c $(MAKE) -C bootstrap bootparse.c bootscanner.c $(MAKE) -C catalog schemapg.h postgres.bki postgres.description postgres.shdescription + $(MAKE) -C replication repl_gram.c repl_scanner.c $(MAKE) -C utils fmgrtab.c fmgroids.h errcodes.h $(MAKE) -C utils/misc guc-file.c @@ -300,12 +302,15 @@ maintainer-clean: distclean rm -f bootstrap/bootparse.c \ bootstrap/bootscanner.c \ parser/gram.c \ - parser/scan.c \ parser/gram.h \ + parser/scan.c \ catalog/schemapg.h \ catalog/postgres.bki \ catalog/postgres.description \ catalog/postgres.shdescription \ + replication/repl_gram.c \ + replication/repl_gram.h \ + replication/repl_scanner.c \ utils/fmgroids.h \ utils/fmgrtab.c \ utils/errcodes.h \ diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 0cd1f941e3..d78b08381e 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -559,7 +559,8 @@ BuildDescForRelation(List *schema) attnum++; attname = entry->colname; - typenameTypeIdModColl(NULL, entry->typeName, &atttypid, &atttypmod, &attcollation); + typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod); + attcollation = GetColumnDefCollation(NULL, entry, atttypid); attdim = list_length(entry->typeName->arrayBounds); if (entry->typeName->setof) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ddcad46b7a..15af6693f5 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6482,6 +6482,9 @@ StartupXLOG(void) { if (recoveryPauseAtTarget) { + ereport(LOG, + (errmsg("recovery has paused"), + errhint("Execute pg_xlog_replay_resume() to continue."))); SetRecoveryPause(true); recoveryPausesHere(); } @@ -8597,7 +8600,7 @@ get_sync_bit(int method) /* * Optimize writes by bypassing kernel cache with O_DIRECT when using - * O_SYNC, O_DSYNC or O_FSYNC. But only if archiving and streaming are + * O_SYNC/O_FSYNC and O_DSYNC. But only if archiving and streaming are * disabled, otherwise the archive command or walsender process will read * the WAL soon after writing it, which is guaranteed to cause a physical * read if we bypassed the kernel cache. We also skip the diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index a98f918a23..48fa6d48b7 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -4736,6 +4736,36 @@ pg_extension_ownercheck(Oid ext_oid, Oid roleid) } /* + * Check whether specified role has CREATEROLE privilege (or is a superuser) + * + * Note: roles do not have owners per se; instead we use this test in + * places where an ownership-like permissions test is needed for a role. + * Be sure to apply it to the role trying to do the operation, not the + * role being operated on! Also note that this generally should not be + * considered enough privilege if the target role is a superuser. + * (We don't handle that consideration here because we want to give a + * separate error message for such cases, so the caller has to deal with it.) + */ +bool +has_createrole_privilege(Oid roleid) +{ + bool result = false; + HeapTuple utup; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); + if (HeapTupleIsValid(utup)) + { + result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole; + ReleaseSysCache(utup); + } + return result; +} + +/* * Fetch pg_default_acl entry for given role, namespace and object type * (object type must be given in pg_default_acl's encoding). * Returns NULL if no such entry. diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index b8b89ab7c1..880b95df02 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -808,13 +808,6 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, NameListToString(objname)); break; - case OBJECT_ROLE: - if (!has_privs_of_role(roleid, address.objectId)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be member of role \"%s\"", - NameListToString(objname)))); - break; case OBJECT_TSDICTIONARY: if (!pg_ts_dict_ownercheck(address.objectId, roleid)) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, @@ -825,6 +818,26 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, NameListToString(objname)); break; + case OBJECT_ROLE: + /* + * We treat roles as being "owned" by those with CREATEROLE priv, + * except that superusers are only owned by superusers. + */ + if (superuser_arg(address.objectId)) + { + if (!superuser_arg(roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser"))); + } + else + { + if (!has_createrole_privilege(roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must have CREATEROLE privilege"))); + } + break; case OBJECT_FDW: case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 3f7d7d913a..325d4523e6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -694,9 +694,5 @@ COMMENT ON FUNCTION ts_debug(text) IS -- CREATE OR REPLACE FUNCTION - format_type(oid, int DEFAULT NULL, oid DEFAULT NULL) - RETURNS text STABLE LANGUAGE internal AS 'format_type'; - -CREATE OR REPLACE FUNCTION pg_start_backup(label text, fast boolean DEFAULT false) RETURNS text STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'; diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index 18e88d2653..a52cb351ac 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -98,7 +98,7 @@ DefineCollation(List *names, List *parameters) Oid collid; HeapTuple tp; - collid = LookupCollation(NULL, defGetQualifiedName(fromEl), -1); + collid = get_collation_oid(defGetQualifiedName(fromEl), false); tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for collation %u", collid); diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 3f25b3bf02..a8ef947240 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -87,7 +87,7 @@ compute_return_type(TypeName *returnType, Oid languageOid, Oid rettype; Type typtup; - typtup = LookupTypeName(NULL, returnType, NULL, NULL); + typtup = LookupTypeName(NULL, returnType, NULL); if (typtup) { @@ -207,7 +207,7 @@ examine_parameter_list(List *parameters, Oid languageOid, Oid toid; Type typtup; - typtup = LookupTypeName(NULL, t, NULL, NULL); + typtup = LookupTypeName(NULL, t, NULL); if (typtup) { if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index e71c311faf..5c6212c64c 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -139,9 +139,12 @@ DefineSequence(CreateSeqStmt *seq) coldef->inhcount = 0; coldef->is_local = true; coldef->is_not_null = true; + coldef->is_from_type = false; coldef->storage = 0; coldef->raw_default = NULL; coldef->cooked_default = NULL; + coldef->collClause = NULL; + coldef->collOid = InvalidOid; coldef->constraints = NIL; null[i - 1] = false; @@ -149,53 +152,53 @@ DefineSequence(CreateSeqStmt *seq) switch (i) { case SEQ_COL_NAME: - coldef->typeName = makeTypeNameFromOid(NAMEOID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(NAMEOID, -1); coldef->colname = "sequence_name"; namestrcpy(&name, seq->sequence->relname); value[i - 1] = NameGetDatum(&name); break; case SEQ_COL_LASTVAL: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "last_value"; value[i - 1] = Int64GetDatumFast(new.last_value); break; case SEQ_COL_STARTVAL: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "start_value"; value[i - 1] = Int64GetDatumFast(new.start_value); break; case SEQ_COL_INCBY: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "increment_by"; value[i - 1] = Int64GetDatumFast(new.increment_by); break; case SEQ_COL_MAXVALUE: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "max_value"; value[i - 1] = Int64GetDatumFast(new.max_value); break; case SEQ_COL_MINVALUE: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "min_value"; value[i - 1] = Int64GetDatumFast(new.min_value); break; case SEQ_COL_CACHE: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "cache_value"; value[i - 1] = Int64GetDatumFast(new.cache_value); break; case SEQ_COL_LOG: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "log_cnt"; value[i - 1] = Int64GetDatum((int64) 1); break; case SEQ_COL_CYCLE: - coldef->typeName = makeTypeNameFromOid(BOOLOID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(BOOLOID, -1); coldef->colname = "is_cycled"; value[i - 1] = BoolGetDatum(new.is_cycled); break; case SEQ_COL_CALLED: - coldef->typeName = makeTypeNameFromOid(BOOLOID, -1, InvalidOid); + coldef->typeName = makeTypeNameFromOid(BOOLOID, -1); coldef->colname = "is_called"; value[i - 1] = BoolGetDatum(false); break; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3be9a6f348..f1264bfb66 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -339,7 +339,7 @@ static void ATPrepAlterColumnType(List **wqueue, AlterTableCmd *cmd, LOCKMODE lockmode); static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno); static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, - const char *colName, TypeName *typeName, LOCKMODE lockmode); + AlterTableCmd *cmd, LOCKMODE lockmode); static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode); static void ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode); static void change_owner_recurse_to_sequences(Oid relationOid, @@ -1433,7 +1433,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence, (errmsg("merging multiple inherited definitions of column \"%s\"", attributeName))); def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1); - typenameTypeIdModColl(NULL, def->typeName, &defTypeId, &deftypmod, &defCollId); + typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod); if (defTypeId != attribute->atttypid || deftypmod != attribute->atttypmod) ereport(ERROR, @@ -1443,6 +1443,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence, errdetail("%s versus %s", TypeNameToString(def->typeName), format_type_be(attribute->atttypid)))); + defCollId = GetColumnDefCollation(NULL, def, defTypeId); if (defCollId != attribute->attcollation) ereport(ERROR, (errcode(ERRCODE_COLLATION_MISMATCH), @@ -1478,14 +1479,16 @@ MergeAttributes(List *schema, List *supers, char relpersistence, def = makeNode(ColumnDef); def->colname = pstrdup(attributeName); def->typeName = makeTypeNameFromOid(attribute->atttypid, - attribute->atttypmod, - attribute->attcollation); + attribute->atttypmod); def->inhcount = 1; def->is_local = false; def->is_not_null = attribute->attnotnull; + def->is_from_type = false; def->storage = attribute->attstorage; def->raw_default = NULL; def->cooked_default = NULL; + def->collClause = NULL; + def->collOid = attribute->attcollation; def->constraints = NIL; inhSchema = lappend(inhSchema, def); newattno[parent_attno - 1] = ++child_attno; @@ -1616,8 +1619,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence, (errmsg("merging column \"%s\" with inherited definition", attributeName))); def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1); - typenameTypeIdModColl(NULL, def->typeName, &defTypeId, &deftypmod, &defcollid); - typenameTypeIdModColl(NULL, newdef->typeName, &newTypeId, &newtypmod, &newcollid); + typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod); + typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod); if (defTypeId != newTypeId || deftypmod != newtypmod) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -1626,6 +1629,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence, errdetail("%s versus %s", TypeNameToString(def->typeName), TypeNameToString(newdef->typeName)))); + defcollid = GetColumnDefCollation(NULL, def, defTypeId); + newcollid = GetColumnDefCollation(NULL, newdef, newTypeId); if (defcollid != newcollid) ereport(ERROR, (errcode(ERRCODE_COLLATION_MISMATCH), @@ -3092,7 +3097,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, cmd->missing_ok, lockmode); break; case AT_AlterColumnType: /* ALTER COLUMN TYPE */ - ATExecAlterColumnType(tab, rel, cmd->name, (TypeName *) cmd->def, lockmode); + ATExecAlterColumnType(tab, rel, cmd, lockmode); break; case AT_ChangeOwner: /* ALTER OWNER */ ATExecChangeOwner(RelationGetRelid(rel), @@ -4129,13 +4134,14 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, Oid ccollid; /* Child column must match by type */ - typenameTypeIdModColl(NULL, colDef->typeName, &ctypeId, &ctypmod, &ccollid); + typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod); if (ctypeId != childatt->atttypid || ctypmod != childatt->atttypmod) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("child table \"%s\" has different type for column \"%s\"", RelationGetRelationName(rel), colDef->colname))); + ccollid = GetColumnDefCollation(NULL, colDef, ctypeId); if (ccollid != childatt->attcollation) ereport(ERROR, (errcode(ERRCODE_COLLATION_MISMATCH), @@ -4201,9 +4207,10 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, MaxHeapAttributeNumber))); } - typeTuple = typenameType(NULL, colDef->typeName, &typmod, &collOid); + typeTuple = typenameType(NULL, colDef->typeName, &typmod); tform = (Form_pg_type) GETSTRUCT(typeTuple); typeOid = HeapTupleGetOid(typeTuple); + collOid = GetColumnDefCollation(NULL, colDef, typeOid); /* make sure datatype is legal for a column */ CheckAttributeType(colDef->colname, typeOid, collOid, false); @@ -4413,7 +4420,7 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC ColumnDef *cdef = makeNode(ColumnDef); cdef->colname = pstrdup("oid"); - cdef->typeName = makeTypeNameFromOid(OIDOID, -1, InvalidOid); + cdef->typeName = makeTypeNameFromOid(OIDOID, -1); cdef->inhcount = 0; cdef->is_local = true; cdef->is_not_null = true; @@ -6471,14 +6478,15 @@ ATPrepAlterColumnType(List **wqueue, AlterTableCmd *cmd, LOCKMODE lockmode) { char *colName = cmd->name; - TypeName *typeName = (TypeName *) cmd->def; + ColumnDef *def = (ColumnDef *) cmd->def; + TypeName *typeName = def->typeName; + Node *transform = def->raw_default; HeapTuple tuple; Form_pg_attribute attTup; AttrNumber attnum; Oid targettype; int32 targettypmod; Oid targetcollid; - Node *transform; NewColumnValue *newval; ParseState *pstate = make_parsestate(NULL); @@ -6512,7 +6520,10 @@ ATPrepAlterColumnType(List **wqueue, colName))); /* Look up the target type */ - typenameTypeIdModColl(NULL, typeName, &targettype, &targettypmod, &targetcollid); + typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod); + + /* And the collation */ + targetcollid = GetColumnDefCollation(NULL, def, targettype); /* make sure datatype is legal for a column */ CheckAttributeType(colName, targettype, targetcollid, false); @@ -6527,7 +6538,7 @@ ATPrepAlterColumnType(List **wqueue, * because we need the expression to be parsed against the original table * rowtype. */ - if (cmd->transform) + if (transform) { RangeTblEntry *rte; @@ -6539,7 +6550,7 @@ ATPrepAlterColumnType(List **wqueue, true); addRTEtoQuery(pstate, rte, false, true, true); - transform = transformExpr(pstate, cmd->transform); + transform = transformExpr(pstate, transform); /* It can't return a set */ if (expression_returns_set(transform)) @@ -6592,16 +6603,13 @@ ATPrepAlterColumnType(List **wqueue, if (ATColumnChangeRequiresRewrite(transform, attnum)) tab->rewrite = true; } - else if (tab->relkind == RELKIND_FOREIGN_TABLE) - { - if (cmd->transform) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("ALTER TYPE USING is not supported on foreign tables"))); - } + else if (transform) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("ALTER TYPE USING is only supported on plain tables"))); - if (tab->relkind == RELKIND_COMPOSITE_TYPE - || tab->relkind == RELKIND_FOREIGN_TABLE) + if (tab->relkind == RELKIND_COMPOSITE_TYPE || + tab->relkind == RELKIND_FOREIGN_TABLE) { /* * For composite types, do this check now. Tables will check @@ -6667,8 +6675,11 @@ ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno) static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, - const char *colName, TypeName *typeName, LOCKMODE lockmode) + AlterTableCmd *cmd, LOCKMODE lockmode) { + char *colName = cmd->name; + ColumnDef *def = (ColumnDef *) cmd->def; + TypeName *typeName = def->typeName; HeapTuple heapTup; Form_pg_attribute attTup; AttrNumber attnum; @@ -6705,9 +6716,11 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, colName))); /* Look up the target type (should not fail, since prep found it) */ - typeTuple = typenameType(NULL, typeName, &targettypmod, &targetcollid); + typeTuple = typenameType(NULL, typeName, &targettypmod); tform = (Form_pg_type) GETSTRUCT(typeTuple); targettype = HeapTupleGetOid(typeTuple); + /* And the collation */ + targetcollid = GetColumnDefCollation(NULL, def, targettype); /* * If there is a default expression for the column, get it and ensure we diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index be1f1d791f..3513256b9a 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -292,7 +292,7 @@ DefineType(List *names, List *parameters) Type likeType; Form_pg_type likeForm; - likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL, NULL); + likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL); likeForm = (Form_pg_type) GETSTRUCT(likeType); internalLength = likeForm->typlen; byValue = likeForm->typbyval; @@ -649,7 +649,7 @@ RemoveTypes(DropStmt *drop) typename = makeTypeNameFromNameList(names); /* Use LookupTypeName here so that shell types can be removed. */ - tup = LookupTypeName(NULL, typename, NULL, NULL); + tup = LookupTypeName(NULL, typename, NULL); if (tup == NULL) { if (!drop->missing_ok) @@ -774,6 +774,7 @@ DefineDomain(CreateDomainStmt *stmt) Oid basetypeoid; Oid domainoid; Oid old_type_oid; + Oid domaincoll; Form_pg_type baseType; int32 basetypeMod; Oid baseColl; @@ -807,7 +808,7 @@ DefineDomain(CreateDomainStmt *stmt) /* * Look up the base type. */ - typeTup = typenameType(NULL, stmt->typeName, &basetypeMod, &baseColl); + typeTup = typenameType(NULL, stmt->typeName, &basetypeMod); baseType = (Form_pg_type) GETSTRUCT(typeTup); basetypeoid = HeapTupleGetOid(typeTup); @@ -825,6 +826,22 @@ DefineDomain(CreateDomainStmt *stmt) errmsg("\"%s\" is not a valid base type for a domain", TypeNameToString(stmt->typeName)))); + /* + * Identify the collation if any + */ + baseColl = baseType->typcollation; + if (stmt->collClause) + domaincoll = get_collation_oid(stmt->collClause->collnames, false); + else + domaincoll = baseColl; + + /* Complain if COLLATE is applied to an uncollatable type */ + if (OidIsValid(domaincoll) && !OidIsValid(baseColl)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("collations are not supported by type %s", + format_type_be(basetypeoid)))); + /* passed by value */ byValue = baseType->typbyval; @@ -1051,7 +1068,7 @@ DefineDomain(CreateDomainStmt *stmt) basetypeMod, /* typeMod value */ typNDims, /* Array dimensions for base type */ typNotNull, /* Type NOT NULL */ - baseColl); + domaincoll); /* * Process constraints which refer to the domain ID returned by TypeCreate @@ -2629,7 +2646,7 @@ AlterTypeOwner(List *names, Oid newOwnerId) typename = makeTypeNameFromNameList(names); /* Use LookupTypeName here so that shell types can be processed */ - tup = LookupTypeName(NULL, typename, NULL, NULL); + tup = LookupTypeName(NULL, typename, NULL); if (tup == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 63f22d8adc..f13eb2891e 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -58,20 +58,7 @@ static void DelRoleMems(const char *rolename, Oid roleid, static bool have_createrole_privilege(void) { - bool result = false; - HeapTuple utup; - - /* Superusers can always do everything */ - if (superuser()) - return true; - - utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId())); - if (HeapTupleIsValid(utup)) - { - result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole; - ReleaseSysCache(utup); - } - return result; + return has_createrole_privilege(GetUserId()); } diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 5576ea259f..794a56e84d 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -120,14 +120,23 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) def->colname = pstrdup(tle->resname); def->typeName = makeTypeNameFromOid(exprType((Node *) tle->expr), - exprTypmod((Node *) tle->expr), - exprCollation((Node *) tle->expr)); + exprTypmod((Node *) tle->expr)); def->inhcount = 0; def->is_local = true; def->is_not_null = false; + def->is_from_type = false; def->storage = 0; def->raw_default = NULL; def->cooked_default = NULL; + def->collClause = NULL; + /* + * XXX Temporary kluge to make regression tests pass. We should + * be able to trust the result of exprCollation more than this. + */ + if (type_is_collatable(exprType((Node *) tle->expr))) + def->collOid = exprCollation((Node *) tle->expr); + else + def->collOid = InvalidOid; def->constraints = NIL; attrList = lappend(attrList, def); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 86a16783f7..b948af604d 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2183,8 +2183,6 @@ _copyTypeName(TypeName *from) COPY_NODE_FIELD(typmods); COPY_SCALAR_FIELD(typemod); COPY_NODE_FIELD(arrayBounds); - COPY_NODE_FIELD(collnames); - COPY_SCALAR_FIELD(collOid); COPY_LOCATION_FIELD(location); return newnode; @@ -2295,9 +2293,12 @@ _copyColumnDef(ColumnDef *from) COPY_SCALAR_FIELD(inhcount); COPY_SCALAR_FIELD(is_local); COPY_SCALAR_FIELD(is_not_null); + COPY_SCALAR_FIELD(is_from_type); COPY_SCALAR_FIELD(storage); COPY_NODE_FIELD(raw_default); COPY_NODE_FIELD(cooked_default); + COPY_NODE_FIELD(collClause); + COPY_SCALAR_FIELD(collOid); COPY_NODE_FIELD(constraints); return newnode; @@ -2515,7 +2516,6 @@ _copyAlterTableCmd(AlterTableCmd *from) COPY_SCALAR_FIELD(subtype); COPY_STRING_FIELD(name); COPY_NODE_FIELD(def); - COPY_NODE_FIELD(transform); COPY_SCALAR_FIELD(behavior); COPY_SCALAR_FIELD(missing_ok); @@ -3063,6 +3063,7 @@ _copyCreateDomainStmt(CreateDomainStmt *from) COPY_NODE_FIELD(domainname); COPY_NODE_FIELD(typeName); + COPY_NODE_FIELD(collClause); COPY_NODE_FIELD(constraints); return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index c234416cf5..c8ee474436 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1007,7 +1007,6 @@ _equalAlterTableCmd(AlterTableCmd *a, AlterTableCmd *b) COMPARE_SCALAR_FIELD(subtype); COMPARE_STRING_FIELD(name); COMPARE_NODE_FIELD(def); - COMPARE_NODE_FIELD(transform); COMPARE_SCALAR_FIELD(behavior); COMPARE_SCALAR_FIELD(missing_ok); @@ -1461,6 +1460,7 @@ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b) { COMPARE_NODE_FIELD(domainname); COMPARE_NODE_FIELD(typeName); + COMPARE_NODE_FIELD(collClause); COMPARE_NODE_FIELD(constraints); return true; @@ -2130,8 +2130,6 @@ _equalTypeName(TypeName *a, TypeName *b) COMPARE_NODE_FIELD(typmods); COMPARE_SCALAR_FIELD(typemod); COMPARE_NODE_FIELD(arrayBounds); - COMPARE_NODE_FIELD(collnames); - COMPARE_SCALAR_FIELD(collOid); COMPARE_LOCATION_FIELD(location); return true; @@ -2226,9 +2224,12 @@ _equalColumnDef(ColumnDef *a, ColumnDef *b) COMPARE_SCALAR_FIELD(inhcount); COMPARE_SCALAR_FIELD(is_local); COMPARE_SCALAR_FIELD(is_not_null); + COMPARE_SCALAR_FIELD(is_from_type); COMPARE_SCALAR_FIELD(storage); COMPARE_NODE_FIELD(raw_default); COMPARE_NODE_FIELD(cooked_default); + COMPARE_NODE_FIELD(collClause); + COMPARE_SCALAR_FIELD(collOid); COMPARE_NODE_FIELD(constraints); return true; diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 0225f19382..d9f1645238 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -427,16 +427,15 @@ makeTypeNameFromNameList(List *names) /* * makeTypeNameFromOid - - * build a TypeName node to represent a type already known by OID/typmod/collation. + * build a TypeName node to represent a type already known by OID/typmod. */ TypeName * -makeTypeNameFromOid(Oid typeOid, int32 typmod, Oid collOid) +makeTypeNameFromOid(Oid typeOid, int32 typmod) { TypeName *n = makeNode(TypeName); n->typeOid = typeOid; n->typemod = typmod; - n->collOid = collOid; n->location = -1; return n; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 4aae2b33a6..06fd7ff818 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2067,9 +2067,12 @@ _outColumnDef(StringInfo str, ColumnDef *node) WRITE_INT_FIELD(inhcount); WRITE_BOOL_FIELD(is_local); WRITE_BOOL_FIELD(is_not_null); + WRITE_BOOL_FIELD(is_from_type); WRITE_INT_FIELD(storage); WRITE_NODE_FIELD(raw_default); WRITE_NODE_FIELD(cooked_default); + WRITE_NODE_FIELD(collClause); + WRITE_OID_FIELD(collOid); WRITE_NODE_FIELD(constraints); } @@ -2085,8 +2088,6 @@ _outTypeName(StringInfo str, TypeName *node) WRITE_NODE_FIELD(typmods); WRITE_INT_FIELD(typemod); WRITE_NODE_FIELD(arrayBounds); - WRITE_NODE_FIELD(collnames); - WRITE_OID_FIELD(collOid); WRITE_LOCATION_FIELD(location); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 5b96b5b0df..373d2adc71 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -132,6 +132,9 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, static List *mergeTableFuncParameters(List *func_args, List *columns); static TypeName *TableFuncTypeName(List *columns); static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); +static void SplitColQualList(List *qualList, + List **constraintList, CollateClause **collClause, + core_yyscan_t yyscanner); %} @@ -221,7 +224,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ %type <node> alter_column_default opclass_item opclass_drop alter_using %type <ival> add_drop opt_asc_desc opt_nulls_order -%type <node> alter_table_cmd alter_type_cmd +%type <node> alter_table_cmd alter_type_cmd opt_collate_clause %type <list> alter_table_cmds alter_type_cmds %type <dbehavior> opt_drop_behavior @@ -400,8 +403,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ %type <list> copy_generic_opt_list copy_generic_opt_arg_list %type <list> copy_options -%type <typnam> Typename SimpleTypename SimpleTypenameWithoutCollation - ConstTypename +%type <typnam> Typename SimpleTypename ConstTypename GenericType Numeric opt_float Character ConstCharacter CharacterWithLength CharacterWithoutLength @@ -619,6 +621,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ %left '^' /* Unary Operators */ %left AT ZONE /* sets precedence for AT TIME ZONE */ +%left COLLATE %right UMINUS %left '[' ']' %left '(' ')' @@ -1746,13 +1749,17 @@ alter_table_cmd: * ALTER TABLE <name> ALTER [COLUMN] <colname> [SET DATA] TYPE <typename> * [ USING <expression> ] */ - | ALTER opt_column ColId opt_set_data TYPE_P Typename alter_using + | ALTER opt_column ColId opt_set_data TYPE_P Typename opt_collate_clause alter_using { AlterTableCmd *n = makeNode(AlterTableCmd); + ColumnDef *def = makeNode(ColumnDef); n->subtype = AT_AlterColumnType; n->name = $3; - n->def = (Node *) $6; - n->transform = $7; + n->def = (Node *) def; + /* We only use these three fields of the ColumnDef node */ + def->typeName = $6; + def->collClause = (CollateClause *) $7; + def->raw_default = $8; $$ = (Node *)n; } /* ALTER TABLE <name> ADD CONSTRAINT ... */ @@ -1981,6 +1988,19 @@ opt_drop_behavior: | /* EMPTY */ { $$ = DROP_RESTRICT; /* default */ } ; +opt_collate_clause: + COLLATE any_name + { + CollateClause *n = makeNode(CollateClause); + n->arg = NULL; + n->collnames = $2; + n->collOid = InvalidOid; + n->location = @1; + $$ = (Node *) n; + } + | /* EMPTY */ { $$ = NULL; } + ; + alter_using: USING a_expr { $$ = $2; } | /* EMPTY */ { $$ = NULL; } @@ -2077,13 +2097,18 @@ alter_type_cmd: $$ = (Node *)n; } /* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> [RESTRICT|CASCADE] */ - | ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_drop_behavior + | ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_collate_clause opt_drop_behavior { AlterTableCmd *n = makeNode(AlterTableCmd); + ColumnDef *def = makeNode(ColumnDef); n->subtype = AT_AlterColumnType; n->name = $3; - n->def = (Node *) $6; - n->behavior = $7; + n->def = (Node *) def; + n->behavior = $8; + /* We only use these three fields of the ColumnDef node */ + def->typeName = $6; + def->collClause = (CollateClause *) $7; + def->raw_default = NULL; $$ = (Node *)n; } ; @@ -2454,8 +2479,16 @@ columnDef: ColId Typename ColQualList ColumnDef *n = makeNode(ColumnDef); n->colname = $1; n->typeName = $2; - n->constraints = $3; + n->inhcount = 0; n->is_local = true; + n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collOid = InvalidOid; + SplitColQualList($3, &n->constraints, &n->collClause, + yyscanner); $$ = (Node *)n; } ; @@ -2464,8 +2497,17 @@ columnOptions: ColId WITH OPTIONS ColQualList { ColumnDef *n = makeNode(ColumnDef); n->colname = $1; - n->constraints = $4; + n->typeName = NULL; + n->inhcount = 0; n->is_local = true; + n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collOid = InvalidOid; + SplitColQualList($4, &n->constraints, &n->collClause, + yyscanner); $$ = (Node *)n; } ; @@ -2486,6 +2528,20 @@ ColConstraint: } | ColConstraintElem { $$ = $1; } | ConstraintAttr { $$ = $1; } + | COLLATE any_name + { + /* + * Note: the CollateClause is momentarily included in + * the list built by ColQualList, but we split it out + * again in SplitColQualList. + */ + CollateClause *n = makeNode(CollateClause); + n->arg = NULL; + n->collnames = $2; + n->collOid = InvalidOid; + n->location = @1; + $$ = (Node *) n; + } ; /* DEFAULT NULL is already the default for Postgres. @@ -2973,8 +3029,12 @@ CreateAsElement: n->inhcount = 0; n->is_local = true; n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; n->raw_default = NULL; n->cooked_default = NULL; + n->collClause = NULL; + n->collOid = InvalidOid; n->constraints = NIL; $$ = (Node *)n; } @@ -6577,7 +6637,7 @@ opt_column: COLUMN { $$ = COLUMN; } | /*EMPTY*/ { $$ = 0; } ; -opt_set_data: SET DATA_P { $$ = 1; } +opt_set_data: SET DATA_P { $$ = 1; } | /*EMPTY*/ { $$ = 0; } ; @@ -7443,7 +7503,8 @@ CreateDomainStmt: CreateDomainStmt *n = makeNode(CreateDomainStmt); n->domainname = $3; n->typeName = $5; - n->constraints = $6; + SplitColQualList($6, &n->constraints, &n->collClause, + yyscanner); $$ = (Node *)n; } ; @@ -9084,13 +9145,21 @@ TableFuncElementList: } ; -TableFuncElement: ColId Typename +TableFuncElement: ColId Typename opt_collate_clause { ColumnDef *n = makeNode(ColumnDef); n->colname = $1; n->typeName = $2; - n->constraints = NIL; + n->inhcount = 0; n->is_local = true; + n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collClause = (CollateClause *) $3; + n->collOid = InvalidOid; + n->constraints = NIL; $$ = (Node *)n; } ; @@ -9151,13 +9220,6 @@ opt_array_bounds: ; SimpleTypename: - SimpleTypenameWithoutCollation opt_collate - { - $$ = $1; - $$->collnames = $2; - } - -SimpleTypenameWithoutCollation: GenericType { $$ = $1; } | Numeric { $$ = $1; } | Bit { $$ = $1; } @@ -9625,6 +9687,14 @@ interval_second: a_expr: c_expr { $$ = $1; } | a_expr TYPECAST Typename { $$ = makeTypeCast($1, $3, @2); } + | a_expr COLLATE any_name + { + CollateClause *n = makeNode(CollateClause); + n->arg = (Expr *) $1; + n->collnames = $3; + n->location = @2; + $$ = (Node *) n; + } | a_expr AT TIME ZONE a_expr { FuncCall *n = makeNode(FuncCall); @@ -10193,14 +10263,6 @@ c_expr: columnref { $$ = $1; } r->location = @1; $$ = (Node *)r; } - | c_expr COLLATE any_name - { - CollateClause *n = makeNode(CollateClause); - n->arg = (Expr *) $1; - n->collnames = $3; - n->location = @2; - $$ = (Node *)n; - } ; /* @@ -12678,15 +12740,6 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, return (Node *) x; } -/* parser_init() - * Initialize to parse one query string - */ -void -parser_init(base_yy_extra_type *yyext) -{ - yyext->parsetree = NIL; /* in case grammar forgets to set it */ -} - /* * Merge the input and output parameters of a table function. */ @@ -12774,6 +12827,57 @@ makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner) return r; } +/* Separate Constraint nodes from COLLATE clauses in a ColQualList */ +static void +SplitColQualList(List *qualList, + List **constraintList, CollateClause **collClause, + core_yyscan_t yyscanner) +{ + ListCell *cell; + ListCell *prev; + ListCell *next; + + *collClause = NULL; + prev = NULL; + for (cell = list_head(qualList); cell; cell = next) + { + Node *n = (Node *) lfirst(cell); + + next = lnext(cell); + if (IsA(n, Constraint)) + { + /* keep it in list */ + prev = cell; + continue; + } + if (IsA(n, CollateClause)) + { + CollateClause *c = (CollateClause *) n; + + if (*collClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple COLLATE clauses not allowed"), + parser_errposition(c->location))); + *collClause = c; + } + else + elog(ERROR, "unexpected node type %d", (int) n->type); + /* remove non-Constraint nodes from qualList */ + qualList = list_delete_cell(qualList, cell, prev); + } + *constraintList = qualList; +} + +/* parser_init() + * Initialize to parse one query string + */ +void +parser_init(base_yy_extra_type *yyext) +{ + yyext->parsetree = NIL; /* in case grammar forgets to set it */ +} + /* * Must undefine this stuff before including scan.c, since it has different * definitions for these macros. diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index ae56532592..7a4f8cc249 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -147,12 +147,6 @@ transformExpr(ParseState *pstate, Node *expr) { TypeCast *tc = (TypeCast *) expr; - if (tc->typeName->collnames) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("COLLATE clause not allowed in cast target"), - parser_errposition(pstate, tc->typeName->location))); - /* * If the subject of the typecast is an ARRAY[] construct and * the target type is an array type, we invoke @@ -2116,13 +2110,16 @@ transformCollateClause(ParseState *pstate, CollateClause *c) newc->arg = (Expr *) transformExpr(pstate, (Node *) c->arg); argtype = exprType((Node *) newc->arg); - /* The unknown type is not collatable, but coerce_type() takes - * care of it separately, so we'll let it go here. */ + /* + * The unknown type is not collatable, but coerce_type() takes + * care of it separately, so we'll let it go here. + */ if (!type_is_collatable(argtype) && argtype != UNKNOWNOID) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("collations are not supported by type %s", - format_type_be(argtype)))); + format_type_be(argtype)), + parser_errposition(pstate, c->location))); newc->collOid = LookupCollation(pstate, c->collnames, c->location); newc->collnames = c->collnames; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 0af9cbd92b..a2d6c59810 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -1313,7 +1313,7 @@ FuncNameAsType(List *funcname) Oid result; Type typtup; - typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, NULL); + typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL); if (typtup == NULL) return InvalidOid; @@ -1500,7 +1500,7 @@ LookupTypeNameOid(const TypeName *typename) Oid result; Type typtup; - typtup = LookupTypeName(NULL, typename, NULL, NULL); + typtup = LookupTypeName(NULL, typename, NULL); if (typtup == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index c7000b9915..488b1425a3 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -1169,7 +1169,8 @@ addRangeTableEntryForFunction(ParseState *pstate, errmsg("column \"%s\" cannot be declared SETOF", attrname), parser_errposition(pstate, n->typeName->location))); - typenameTypeIdModColl(pstate, n->typeName, &attrtype, &attrtypmod, &attrcollation); + typenameTypeIdAndMod(pstate, n->typeName, &attrtype, &attrtypmod); + attrcollation = GetColumnDefCollation(pstate, n, attrtype); eref->colnames = lappend(eref->colnames, makeString(attrname)); rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype); rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod); diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 20cb47e712..2ba9bf5181 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -29,8 +29,6 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ); -static Oid typenameCollation(ParseState *pstate, const TypeName *typeName, - Type typ); /* @@ -38,8 +36,7 @@ static Oid typenameCollation(ParseState *pstate, const TypeName *typeName, * Given a TypeName object, lookup the pg_type syscache entry of the type. * Returns NULL if no such type can be found. If the type is found, * the typmod value represented in the TypeName struct is computed and - * stored into *typmod_p, and the collation is looked up and stored into - * *colloid_p. + * stored into *typmod_p. * * NB: on success, the caller must ReleaseSysCache the type tuple when done * with it. @@ -54,18 +51,15 @@ static Oid typenameCollation(ParseState *pstate, const TypeName *typeName, * found but is a shell, and there is typmod decoration, an error will be * thrown --- this is intentional. * - * colloid_p can also be null. - * * pstate is only used for error location info, and may be NULL. */ Type LookupTypeName(ParseState *pstate, const TypeName *typeName, - int32 *typmod_p, Oid *collid_p) + int32 *typmod_p) { Oid typoid; HeapTuple tup; int32 typmod; - Oid collid; if (typeName->names == NIL) { @@ -180,28 +174,22 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName, if (typmod_p) *typmod_p = typmod; - collid = typenameCollation(pstate, typeName, (Type) tup); - - if (collid_p) - *collid_p = collid; - return (Type) tup; } /* - * typenameType - given a TypeName, return a Type structure, typmod, and - * collation + * typenameType - given a TypeName, return a Type structure and typmod * * This is equivalent to LookupTypeName, except that this will report * a suitable error message if the type cannot be found or is not defined. * Callers of this can therefore assume the result is a fully valid type. */ Type -typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, Oid *collid_p) +typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p) { Type tup; - tup = LookupTypeName(pstate, typeName, typmod_p, collid_p); + tup = LookupTypeName(pstate, typeName, typmod_p); if (tup == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -229,7 +217,7 @@ typenameTypeId(ParseState *pstate, const TypeName *typeName) Oid typoid; Type tup; - tup = typenameType(pstate, typeName, NULL, NULL); + tup = typenameType(pstate, typeName, NULL); typoid = HeapTupleGetOid(tup); ReleaseSysCache(tup); @@ -248,25 +236,7 @@ typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, { Type tup; - tup = typenameType(pstate, typeName, typmod_p, NULL); - *typeid_p = HeapTupleGetOid(tup); - ReleaseSysCache(tup); -} - -/* - * typenameTypeIdModColl - given a TypeName, return the type's OID, - * typmod, and collation - * - * This is equivalent to typenameType, but we only hand back the type OID, - * typmod, and collation, not the syscache entry. - */ -void -typenameTypeIdModColl(ParseState *pstate, const TypeName *typeName, - Oid *typeid_p, int32 *typmod_p, Oid *collid_p) -{ - Type tup; - - tup = typenameType(pstate, typeName, typmod_p, collid_p); + tup = typenameType(pstate, typeName, typmod_p); *typeid_p = HeapTupleGetOid(tup); ReleaseSysCache(tup); } @@ -381,62 +351,6 @@ typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ) } /* - * typenameCollation - given a TypeName, return the collation OID - * - * This will throw an error if the TypeName includes a collation but - * the data type does not support collations. - * - * The actual type OID represented by the TypeName must already have been - * looked up, and is passed as "typ". - * - * pstate is only used for error location info, and may be NULL. - */ -static Oid -typenameCollation(ParseState *pstate, const TypeName *typeName, Type typ) -{ - Oid typcollation = ((Form_pg_type) GETSTRUCT(typ))->typcollation; - - /* return prespecified collation OID if no collation name specified */ - if (typeName->collnames == NIL) - { - if (typeName->collOid == InvalidOid) - return typcollation; - else - return typeName->collOid; - } - - if (!OidIsValid(typcollation)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("collations are not supported by type %s", - format_type_be(HeapTupleGetOid(typ))), - parser_errposition(pstate, typeName->location))); - - return LookupCollation(pstate, typeName->collnames, typeName->location); -} - -/* - * LookupCollation - * - * Look up collation by name, return OID, with support for error - * location. - */ -Oid -LookupCollation(ParseState *pstate, List *collnames, int location) -{ - Oid colloid; - ParseCallbackState pcbstate; - - setup_parser_errposition_callback(&pcbstate, pstate, location); - - colloid = get_collation_oid(collnames, false); - - cancel_parser_errposition_callback(&pcbstate); - - return colloid; -} - -/* * appendTypeNameToBuffer * Append a string representing the name of a TypeName to a StringInfo. * This is the shared guts of TypeNameToString and TypeNameListToString. @@ -516,6 +430,72 @@ TypeNameListToString(List *typenames) return string.data; } +/* + * LookupCollation + * + * Look up collation by name, return OID, with support for error location. + */ +Oid +LookupCollation(ParseState *pstate, List *collnames, int location) +{ + Oid colloid; + ParseCallbackState pcbstate; + + if (pstate) + setup_parser_errposition_callback(&pcbstate, pstate, location); + + colloid = get_collation_oid(collnames, false); + + if (pstate) + cancel_parser_errposition_callback(&pcbstate); + + return colloid; +} + +/* + * GetColumnDefCollation + * + * Get the collation to be used for a column being defined, given the + * ColumnDef node and the previously-determined column type OID. + * + * pstate is only used for error location purposes, and can be NULL. + */ +Oid +GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid) +{ + Oid result; + Oid typcollation = get_typcollation(typeOid); + int location = -1; + + if (coldef->collClause) + { + /* We have a raw COLLATE clause, so look up the collation */ + location = coldef->collClause->location; + result = LookupCollation(pstate, coldef->collClause->collnames, + location); + } + else if (OidIsValid(coldef->collOid)) + { + /* Precooked collation spec, use that */ + result = coldef->collOid; + } + else + { + /* Use the type's default collation if any */ + result = typcollation; + } + + /* Complain if COLLATE is applied to an uncollatable type */ + if (OidIsValid(result) && !OidIsValid(typcollation)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("collations are not supported by type %s", + format_type_be(typeOid)), + parser_errposition(pstate, location))); + + return result; +} + /* return a Type structure, given a type id */ /* NB: caller must ReleaseSysCache the type tuple when done with it */ Type diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 61ce840a5e..e876853af0 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -627,13 +627,16 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation) def = makeNode(ColumnDef); def->colname = pstrdup(attributeName); def->typeName = makeTypeNameFromOid(attribute->atttypid, - attribute->atttypmod, - attribute->attcollation); + attribute->atttypmod); def->inhcount = 0; def->is_local = true; def->is_not_null = attribute->attnotnull; + def->is_from_type = false; + def->storage = 0; def->raw_default = NULL; def->cooked_default = NULL; + def->collClause = NULL; + def->collOid = attribute->attcollation; def->constraints = NIL; /* @@ -822,7 +825,7 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename) AssertArg(ofTypename); - tuple = typenameType(NULL, ofTypename, NULL, NULL); + tuple = typenameType(NULL, ofTypename, NULL); typ = (Form_pg_type) GETSTRUCT(tuple); ofTypeId = HeapTupleGetOid(tuple); ofTypename->typeOid = ofTypeId; /* cached for later */ @@ -837,16 +840,24 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename) for (i = 0; i < tupdesc->natts; i++) { Form_pg_attribute attr = tupdesc->attrs[i]; - ColumnDef *n = makeNode(ColumnDef); + ColumnDef *n; if (attr->attisdropped) continue; + n = makeNode(ColumnDef); n->colname = pstrdup(NameStr(attr->attname)); - n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod, attr->attcollation); - n->constraints = NULL; + n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod); + n->inhcount = 0; n->is_local = true; + n->is_not_null = false; n->is_from_type = true; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collClause = NULL; + n->collOid = attr->attcollation; + n->constraints = NIL; cxt->columns = lappend(cxt->columns, n); } DecrTupleDescRefCount(tupdesc); @@ -2445,9 +2456,28 @@ static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column) { /* - * All we really need to do here is verify that the type is valid. + * All we really need to do here is verify that the type is valid, + * including any collation spec that might be present. */ - Type ctype = typenameType(cxt->pstate, column->typeName, NULL, NULL); + Type ctype = typenameType(cxt->pstate, column->typeName, NULL); + + if (column->collClause) + { + Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype); + Oid collOid; + + collOid = LookupCollation(cxt->pstate, + column->collClause->collnames, + column->collClause->location); + /* Complain if COLLATE is applied to an uncollatable type */ + if (!OidIsValid(typtup->typcollation)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("collations are not supported by type %s", + format_type_be(HeapTupleGetOid(ctype))), + parser_errposition(cxt->pstate, + column->collClause->location))); + } ReleaseSysCache(ctype); } diff --git a/src/backend/replication/README b/src/backend/replication/README index 744ddc7fe8..7585429805 100644 --- a/src/backend/replication/README +++ b/src/backend/replication/README @@ -4,11 +4,11 @@ Walreceiver - libpqwalreceiver API ---------------------------------- The transport-specific part of walreceiver, responsible for connecting to -the primary server and receiving WAL files, is loaded dynamically to avoid -having to link the main server binary with libpq. The dynamically loaded -module is in libpqwalreceiver subdirectory. +the primary server, receiving WAL files and sending messages, is loaded +dynamically to avoid having to link the main server binary with libpq. +The dynamically loaded module is in libpqwalreceiver subdirectory. -The dynamically loaded module implements three functions: +The dynamically loaded module implements four functions: bool walrcv_connect(char *conninfo, XLogRecPtr startpoint) @@ -16,7 +16,6 @@ bool walrcv_connect(char *conninfo, XLogRecPtr startpoint) Establish connection to the primary, and starts streaming from 'startpoint'. Returns true on success. - bool walrcv_receive(int timeout, unsigned char *type, char **buffer, int *len) Retrieve any message available through the connection, blocking for @@ -26,6 +25,10 @@ otherwise false. On success, a pointer to the message payload is stored in returned buffer is valid until the next call to walrcv_* functions, the caller should not attempt freeing it. +void walrcv_send(const char *buffer, int nbytes) + +Send a message to XLOG stream. + void walrcv_disconnect(void); Disconnect. @@ -45,11 +48,15 @@ to fetch more WAL (if streaming replication is configured). Walreceiver is a postmaster subprocess, so the startup process can't fork it directly. Instead, it sends a signal to postmaster, asking postmaster to launch it. Before that, however, startup process fills in WalRcvData->conninfo, -and initializes the starting point in WalRcvData->receivedUpto. +and initializes the starting point in WalRcvData->receiveStart. As walreceiver receives WAL from the master server, and writes and flushes -it to disk (in pg_xlog), it updates WalRcvData->receivedUpto. Startup process -polls that to know how far it can proceed with WAL replay. +it to disk (in pg_xlog), it updates WalRcvData->receivedUpto and signals +the startup process to know how far WAL replay can advance. + +Walreceiver sends information about replication progress to the master server +whenever either it writes or flushes new WAL, or the specified interval elapses. +This is used for reporting purpose. Walsender IPC ------------- @@ -80,11 +87,9 @@ phase. A walsenders will look like a regular backends until it's done with the initialization and has marked itself in PMSignal array, and at process termination, after unmarking the PMSignal slot. -Each walsender allocates an entry from the WalSndCtl array, and advertises -there how far it has streamed WAL already. This is used at checkpoints, to -avoid recycling WAL that hasn't been streamed to a slave yet. However, -that doesn't stop such WAL from being recycled when the connection is not -established. +Each walsender allocates an entry from the WalSndCtl array, and tracks +information about replication progress. User can monitor them via +statistics views. Walsender - walreceiver protocol diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index db4cc640e4..d21568cb21 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -219,7 +219,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ptr.xrecoff = logseg * XLogSegSize + TAR_SEND_SIZE * i; /* - * Some old compilers, e.g. 2.95.3/x86, think that passing + * Some old compilers, e.g. gcc 2.95.3/x86, think that passing * a struct in the same function as a longjump might clobber * a variable. bjm 2011-02-04 * http://lists.apple.com/archives/xcode-users/2003/Dec//msg00051.html diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index f6c3538650..3ef9cdd87c 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -37,7 +37,7 @@ * Portions Copyright (c) 2010-2011, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL$ + * src/backend/replication/syncrep.c * *------------------------------------------------------------------------- */ @@ -62,7 +62,7 @@ #include "utils/ps_status.h" /* User-settable parameters for sync rep */ -bool sync_rep_mode = false; /* Only set in user backends */ +bool synchronous_replication = false; /* Only set in user backends */ char *SyncRepStandbyNames; static bool sync_standbys_defined = false; /* Is there at least one name? */ @@ -225,7 +225,7 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) /* * Insert MyProc into SyncRepQueue, maintaining sorted invariant. * - * Usually we will go at tail of queue, though its possible that we arrive + * Usually we will go at tail of queue, though it's possible that we arrive * here out of order, so start at tail and work back to insertion point. */ static void @@ -420,9 +420,7 @@ SyncRepGetStandbyPriority(void) /* syntax error in list */ pfree(rawstring); list_free(elemlist); - ereport(FATAL, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for parameter \"synchronous_standby_names\""))); + /* GUC machinery will have already complained - no need to do again */ return 0; } @@ -447,9 +445,9 @@ SyncRepGetStandbyPriority(void) } /* - * Walk queue from head setting setting the state of any backends that - * need to be woken, remove them from the queue and then wake them. - * Set all = true to wake whole queue, or just up to LSN. + * Walk queue from head. Set the state of any backends that need to be woken, + * remove them from the queue, and then wake them. Pass all = true to wake + * whole queue; otherwise, just wake up to the walsender's LSN. * * Must hold SyncRepLock. */ @@ -563,7 +561,7 @@ assign_synchronous_standby_names(const char *newval, bool doit, GucSource source /* syntax error in list */ pfree(rawstring); list_free(elemlist); - ereport(FATAL, + ereport(GUC_complaint_elevel(source), (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for parameter \"synchronous_standby_names\""))); return NULL; diff --git a/src/backend/storage/ipc/shmqueue.c b/src/backend/storage/ipc/shmqueue.c index 5d684b2b85..d7ec3013a6 100644 --- a/src/backend/storage/ipc/shmqueue.c +++ b/src/backend/storage/ipc/shmqueue.c @@ -157,7 +157,7 @@ SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset) /*-------------------- * SHMQueuePrev -- Get the previous element from a queue * - * Same as SHMQueueNext, just starting at tail and moving towards head + * Same as SHMQueueNext, just starting at tail and moving towards head. * All other comments and usage applies. */ Pointer diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index f85e0bbd00..b56bb74bdc 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -18,7 +18,6 @@ #include <ctype.h> #include "catalog/namespace.h" -#include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/lsyscache.h" @@ -29,8 +28,7 @@ #define MAX_INT32_LEN 11 static char *format_type_internal(Oid type_oid, int32 typemod, - bool typemod_given, bool allow_invalid, - Oid collation_oid); + bool typemod_given, bool allow_invalid); static char *printTypmod(const char *typname, int32 typmod, Oid typmodout); static char * psnprintf(size_t len, const char *fmt,...) @@ -69,7 +67,6 @@ format_type(PG_FUNCTION_ARGS) { Oid type_oid; int32 typemod; - Oid collation_oid; char *result; /* Since this function is not strict, we must test for null args */ @@ -77,14 +74,13 @@ format_type(PG_FUNCTION_ARGS) PG_RETURN_NULL(); type_oid = PG_GETARG_OID(0); - collation_oid = PG_ARGISNULL(2) ? InvalidOid : PG_GETARG_OID(2); if (PG_ARGISNULL(1)) - result = format_type_internal(type_oid, -1, false, true, collation_oid); + result = format_type_internal(type_oid, -1, false, true); else { typemod = PG_GETARG_INT32(1); - result = format_type_internal(type_oid, typemod, true, true, collation_oid); + result = format_type_internal(type_oid, typemod, true, true); } PG_RETURN_TEXT_P(cstring_to_text(result)); @@ -99,7 +95,7 @@ format_type(PG_FUNCTION_ARGS) char * format_type_be(Oid type_oid) { - return format_type_internal(type_oid, -1, false, false, InvalidOid); + return format_type_internal(type_oid, -1, false, false); } /* @@ -108,15 +104,14 @@ format_type_be(Oid type_oid) char * format_type_with_typemod(Oid type_oid, int32 typemod) { - return format_type_internal(type_oid, typemod, true, false, InvalidOid); + return format_type_internal(type_oid, typemod, true, false); } static char * format_type_internal(Oid type_oid, int32 typemod, - bool typemod_given, bool allow_invalid, - Oid collation_oid) + bool typemod_given, bool allow_invalid) { bool with_typemod = typemod_given && (typemod >= 0); HeapTuple tuple; @@ -322,12 +317,6 @@ format_type_internal(Oid type_oid, int32 typemod, ReleaseSysCache(tuple); - if (collation_oid && collation_oid != DEFAULT_COLLATION_OID) - { - char *collstr = generate_collation_name(collation_oid); - buf = psnprintf(strlen(buf) + 10 + strlen(collstr), "%s COLLATE %s", buf, collstr); - } - return buf; } @@ -431,7 +420,7 @@ oidvectortypes(PG_FUNCTION_ARGS) for (num = 0; num < numargs; num++) { char *typename = format_type_internal(oidArray->values[num], -1, - false, true, InvalidOid); + false, true); size_t slen = strlen(typename); if (left < (slen + 2)) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 025edf0838..7cbd0222cb 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5082,8 +5082,9 @@ get_rule_expr(Node *node, deparse_context *context, if (!PRETTY_PAREN(context)) appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, node); - appendStringInfo(buf, " COLLATE %s", generate_collation_name(collate->collOid)); + get_rule_expr_paren(arg, context, showimplicit, node); + appendStringInfo(buf, " COLLATE %s", + generate_collation_name(collate->collOid)); if (!PRETTY_PAREN(context)) appendStringInfoChar(buf, ')'); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 0bf1845599..d1b1c17427 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -759,7 +759,7 @@ static struct config_bool ConfigureNamesBool[] = gettext_noop("Requests synchronous replication."), NULL }, - &sync_rep_mode, + &synchronous_replication, false, NULL, NULL }, { diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index ce24d6101d..acd251415d 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -1388,6 +1388,8 @@ setup_depend(void) " FROM pg_ts_template;\n", "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' " " FROM pg_ts_config;\n", + "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' " + " FROM pg_collation;\n", "INSERT INTO pg_shdepend SELECT 0,0,0,0, tableoid,oid, 'p' " " FROM pg_authid;\n", NULL diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 12b22bc256..472760edf1 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -54,10 +54,12 @@ static int numTables; static int numTypes; static int numFuncs; static int numOperators; +static int numCollations; static DumpableObject **tblinfoindex; static DumpableObject **typinfoindex; static DumpableObject **funinfoindex; static DumpableObject **oprinfoindex; +static DumpableObject **collinfoindex; static void flagInhTables(TableInfo *tbinfo, int numTables, @@ -105,7 +107,6 @@ getSchemaData(int *numTablesPtr) int numCasts; int numOpclasses; int numOpfamilies; - int numCollations; int numConversions; int numTSParsers; int numTSTemplates; @@ -187,6 +188,7 @@ getSchemaData(int *numTablesPtr) if (g_verbose) write_msg(NULL, "reading user-defined collations\n"); collinfo = getCollations(&numCollations); + collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo)); if (g_verbose) write_msg(NULL, "reading user-defined conversions\n"); @@ -784,6 +786,17 @@ findOprByOid(Oid oid) return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators); } +/* + * findCollationByOid + * finds the entry (in collinfo) of the collation with the given oid + * returns NULL if not found + */ +CollInfo * +findCollationByOid(Oid oid) +{ + return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations); +} + /* * findParentsByOid diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c index 625e093066..540ca5405a 100644 --- a/src/bin/pg_dump/pg_backup_directory.c +++ b/src/bin/pg_dump/pg_backup_directory.c @@ -17,7 +17,7 @@ * sync. * * - * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 2000, Philip Warner * diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index dfbdcadd14..0884517331 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -5502,6 +5502,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) int i_attalign; int i_attislocal; int i_attoptions; + int i_attcollation; PGresult *res; int ntups; bool hasdefaults; @@ -5541,13 +5542,20 @@ getTableAttrs(TableInfo *tblinfo, int numTables) if (g_fout->remoteVersion >= 90100) { - /* attcollation is new in 9.1 */ + /* + * attcollation is new in 9.1. Since we only want to dump + * COLLATE clauses for attributes whose collation is different + * from their type's default, we use a CASE here to suppress + * uninteresting attcollations cheaply. + */ appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, " "a.attstattarget, a.attstorage, t.typstorage, " "a.attnotnull, a.atthasdef, a.attisdropped, " "a.attlen, a.attalign, a.attislocal, " - "pg_catalog.format_type(t.oid,a.atttypmod,a.attcollation) AS atttypname, " - "array_to_string(attoptions, ', ') AS attoptions " + "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " + "array_to_string(a.attoptions, ', ') AS attoptions, " + "CASE WHEN a.attcollation <> t.typcollation " + "THEN a.attcollation ELSE 0 END AS attcollation " "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::pg_catalog.oid " @@ -5563,7 +5571,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) "a.attnotnull, a.atthasdef, a.attisdropped, " "a.attlen, a.attalign, a.attislocal, " "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " - "array_to_string(attoptions, ', ') AS attoptions " + "array_to_string(a.attoptions, ', ') AS attoptions, " + "0 AS attcollation " "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::pg_catalog.oid " @@ -5579,7 +5588,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) "a.attnotnull, a.atthasdef, a.attisdropped, " "a.attlen, a.attalign, a.attislocal, " "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, " - "'' AS attoptions " + "'' AS attoptions, 0 AS attcollation " "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t " "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::pg_catalog.oid " @@ -5600,7 +5609,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) "false AS attisdropped, a.attlen, " "a.attalign, false AS attislocal, " "format_type(t.oid,a.atttypmod) AS atttypname, " - "'' AS attoptions " + "'' AS attoptions, 0 AS attcollation " "FROM pg_attribute a LEFT JOIN pg_type t " "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::oid " @@ -5618,7 +5627,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) "attlen, attalign, " "false AS attislocal, " "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, " - "'' AS attoptions " + "'' AS attoptions, 0 AS attcollation " "FROM pg_attribute a " "WHERE attrelid = '%u'::oid " "AND attnum > 0::int2 " @@ -5645,6 +5654,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) i_attalign = PQfnumber(res, "attalign"); i_attislocal = PQfnumber(res, "attislocal"); i_attoptions = PQfnumber(res, "attoptions"); + i_attcollation = PQfnumber(res, "attcollation"); tbinfo->numatts = ntups; tbinfo->attnames = (char **) malloc(ntups * sizeof(char *)); @@ -5660,6 +5670,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool)); tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *)); tbinfo->attoptions = (char **) malloc(ntups * sizeof(char *)); + tbinfo->attcollation = (Oid *) malloc(ntups * sizeof(Oid)); tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool)); tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool)); @@ -5685,6 +5696,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't'); tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't'); tbinfo->attoptions[j] = strdup(PQgetvalue(res, j, i_attoptions)); + tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation)); tbinfo->attrdefs[j] = NULL; /* fix below */ if (PQgetvalue(res, j, i_atthasdef)[0] == 't') hasdefaults = true; @@ -7359,7 +7371,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) "typanalyze::pg_catalog.oid AS typanalyzeoid, " "typcategory, typispreferred, " "typdelim, typbyval, typalign, typstorage, " - "(typcollation = (SELECT oid FROM pg_catalog.pg_collation WHERE collname = 'default')) AS typcollatable, " + "(typcollation <> 0) AS typcollatable, " "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault " "FROM pg_catalog.pg_type " "WHERE oid = '%u'::pg_catalog.oid", @@ -7736,6 +7748,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) char *typnotnull; char *typdefn; char *typdefault; + Oid typcollation; bool typdefault_is_literal = false; /* Set proper schema search path so type references list correctly */ @@ -7745,11 +7758,14 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) if (g_fout->remoteVersion >= 90100) { /* typcollation is new in 9.1 */ - appendPQExpBuffer(query, "SELECT typnotnull, " - "pg_catalog.format_type(typbasetype, typtypmod, typcollation) AS typdefn, " - "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, " - "typdefault " + appendPQExpBuffer(query, "SELECT t.typnotnull, " + "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, " + "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, " + "t.typdefault, " + "CASE WHEN t.typcollation <> u.typcollation " + "THEN t.typcollation ELSE 0 END AS typcollation " "FROM pg_catalog.pg_type t " + "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) " "WHERE t.oid = '%u'::pg_catalog.oid", tyinfo->dobj.catId.oid); } @@ -7759,7 +7775,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) appendPQExpBuffer(query, "SELECT typnotnull, " "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, " "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, " - "typdefault " + "typdefault, 0 AS typcollation " "FROM pg_catalog.pg_type " "WHERE oid = '%u'::pg_catalog.oid", tyinfo->dobj.catId.oid); @@ -7790,6 +7806,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) } else typdefault = NULL; + typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation"))); if (binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid); @@ -7799,6 +7816,22 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) fmtId(tyinfo->dobj.name), typdefn); + /* Print collation only if different from base type's collation */ + if (OidIsValid(typcollation)) + { + CollInfo *coll; + + coll = findCollationByOid(typcollation); + if (coll) + { + /* always schema-qualify, don't try to be smart */ + appendPQExpBuffer(q, " COLLATE %s.", + fmtId(coll->dobj.namespace->dobj.name)); + appendPQExpBuffer(q, "%s", + fmtId(coll->dobj.name)); + } + } + if (typnotnull[0] == 't') appendPQExpBuffer(q, " NOT NULL"); @@ -11966,6 +11999,22 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) tbinfo->atttypmod[j])); } + /* Add collation if not default for the type */ + if (OidIsValid(tbinfo->attcollation[j])) + { + CollInfo *coll; + + coll = findCollationByOid(tbinfo->attcollation[j]); + if (coll) + { + /* always schema-qualify, don't try to be smart */ + appendPQExpBuffer(q, " COLLATE %s.", + fmtId(coll->dobj.namespace->dobj.name)); + appendPQExpBuffer(q, "%s", + fmtId(coll->dobj.name)); + } + } + if (has_default) appendPQExpBuffer(q, " DEFAULT %s", tbinfo->attrdefs[j]->adef_expr); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 94b7a6bf92..113ecb1846 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -272,6 +272,7 @@ typedef struct _tableInfo char *attalign; /* attribute align, used by binary_upgrade */ bool *attislocal; /* true if attr has local definition */ char **attoptions; /* per-attribute options */ + Oid *attcollation; /* per-attribute collation selection */ /* * Note: we need to store per-attribute notnull, default, and constraint @@ -510,6 +511,7 @@ extern TableInfo *findTableByOid(Oid oid); extern TypeInfo *findTypeByOid(Oid oid); extern FuncInfo *findFuncByOid(Oid oid); extern OprInfo *findOprByOid(Oid oid); +extern CollInfo *findCollationByOid(Oid oid); extern void simple_oid_list_append(SimpleOidList *list, Oid val); extern void simple_string_list_append(SimpleStringList *list, const char *val); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index e21ee0a835..22a0b89b44 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201103061 +#define CATALOG_VERSION_NO 201103101 #endif diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h index 42a70e8f25..6decfb13b3 100644 --- a/src/include/catalog/pg_collation.h +++ b/src/include/catalog/pg_collation.h @@ -5,10 +5,11 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL$ + * IDENTIFICATION + * src/include/catalog/pg_collation.h * * NOTES * the genbki.pl script reads this file and generates .bki diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h index ada807ad71..3ab5344c9d 100644 --- a/src/include/catalog/pg_foreign_table.h +++ b/src/include/catalog/pg_foreign_table.h @@ -3,7 +3,7 @@ * pg_foreign_table.h * definition of the system "foreign table" relation (pg_foreign_table) * - * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_foreign_table.h diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 0533e5a686..cff64ba6b0 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -1100,8 +1100,8 @@ DATA(insert OID = 1078 ( bpcharcmp PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 DESCR("less-equal-greater"); DATA(insert OID = 1080 ( hashbpchar PGNSP PGUID 12 1 0 0 f f f t f i 1 0 23 "1042" _null_ _null_ _null_ _null_ hashbpchar _null_ _null_ _null_ )); DESCR("hash"); -DATA(insert OID = 1081 ( format_type PGNSP PGUID 12 1 0 0 f f f f f s 3 0 25 "26 23 26" _null_ _null_ _null_ _null_ format_type _null_ _null_ _null_ )); -DESCR("format a type OID, atttypmod, and collation OID to canonical SQL"); +DATA(insert OID = 1081 ( format_type PGNSP PGUID 12 1 0 0 f f f f f s 2 0 25 "26 23" _null_ _null_ _null_ _null_ format_type _null_ _null_ _null_ )); +DESCR("format a type oid and atttypmod to canonical SQL"); DATA(insert OID = 1084 ( date_in PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1082 "2275" _null_ _null_ _null_ _null_ date_in _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 1085 ( date_out PGNSP PGUID 12 1 0 0 f f f t f s 1 0 2275 "1082" _null_ _null_ _null_ _null_ date_out _null_ _null_ _null_ )); diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 8b7db798b9..6691b0dc77 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -68,7 +68,7 @@ extern RangeVar *makeRangeVar(char *schemaname, char *relname, int location); extern TypeName *makeTypeName(char *typnam); extern TypeName *makeTypeNameFromNameList(List *names); -extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod, Oid collOid); +extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod); extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype, List *args, Oid collid, CoercionForm fformat); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 287e9f523f..9d4515cb27 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -168,8 +168,7 @@ typedef struct Query * specify the type by OID than by name. If "names" is NIL then the * actual type OID is given by typeOid, otherwise typeOid is unused. * Similarly, if "typmods" is NIL then the actual typmod is expected to - * be prespecified in typemod, otherwise typemod is unused. Similarly - * for collnames/collOid. + * be prespecified in typemod, otherwise typemod is unused. * * If pct_type is TRUE, then names is actually a field name and we look up * the type of that field. Otherwise (the normal case), names is a type @@ -185,8 +184,6 @@ typedef struct TypeName List *typmods; /* type modifier expression(s) */ int32 typemod; /* prespecified type modifier */ List *arrayBounds; /* array bounds */ - List *collnames; /* collation name */ - Oid collOid; /* collation by OID */ int location; /* token location, or -1 if unknown */ } TypeName; @@ -468,6 +465,10 @@ typedef struct RangeFunction * how this ColumnDef node was created (by parsing, or by inheritance * from an existing relation). We should never have both in the same node! * + * Similarly, we may have a COLLATE specification in either raw form + * (represented as a CollateClause with arg==NULL) or cooked form + * (the collation's OID). + * * The constraints list may contain a CONSTR_DEFAULT item in a raw * parsetree produced by gram.y, but transformCreateStmt will remove * the item and set raw_default instead. CONSTR_DEFAULT items @@ -485,6 +486,8 @@ typedef struct ColumnDef char storage; /* attstorage setting, or 0 for default */ Node *raw_default; /* default value (untransformed parse tree) */ Node *cooked_default; /* default value (transformed expr tree) */ + CollateClause *collClause; /* untransformed COLLATE spec, if any */ + Oid collOid; /* collation OID (InvalidOid if not set) */ List *constraints; /* other constraints on column */ } ColumnDef; @@ -1202,9 +1205,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ AlterTableType subtype; /* Type of table alteration to apply */ char *name; /* column, constraint, or trigger to act on, * or new owner or tablespace */ - Node *def; /* definition of new column, column type, - * index, constraint, or parent table */ - Node *transform; /* transformation expr for ALTER TYPE */ + Node *def; /* definition of new column, index, + * constraint, or parent table */ DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */ bool missing_ok; /* skip error if missing? */ bool validated; @@ -1819,6 +1821,7 @@ typedef struct CreateDomainStmt NodeTag type; List *domainname; /* qualified name (list of Value strings) */ TypeName *typeName; /* the base type */ + CollateClause *collClause; /* untransformed COLLATE spec, if any */ List *constraints; /* constraints (list of Constraint nodes) */ } CreateDomainStmt; diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index 8621ab678d..92c9ecba4a 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -20,21 +20,19 @@ typedef HeapTuple Type; extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName, - int32 *typmod_p, Oid *collid_p); + int32 *typmod_p); extern Type typenameType(ParseState *pstate, const TypeName *typeName, - int32 *typmod_p, Oid *collid_p); - -extern Oid LookupCollation(ParseState *pstate, List *collnames, int location); - + int32 *typmod_p); extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName); extern void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, - Oid *typeid_p, int32 *typmod_p); -extern void typenameTypeIdModColl(ParseState *pstate, const TypeName *typeName, - Oid *typeid_p, int32 *typmod_p, Oid *collid_p); + Oid *typeid_p, int32 *typmod_p); extern char *TypeNameToString(const TypeName *typeName); extern char *TypeNameListToString(List *typenames); +extern Oid LookupCollation(ParseState *pstate, List *collnames, int location); +extern Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid); + extern Type typeidType(Oid id); extern Oid typeTypeId(Type tp); diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h index af6a36621f..831c33fb4a 100644 --- a/src/include/replication/basebackup.h +++ b/src/include/replication/basebackup.h @@ -3,7 +3,7 @@ * basebackup.h * Exports from replication/basebackup.c. * - * Portions Copyright (c) 2010-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2011, PostgreSQL Global Development Group * * src/include/replication/walsender.h * diff --git a/src/include/replication/syncrep.h b/src/include/replication/syncrep.h index f4eb3c9f04..9171eb6176 100644 --- a/src/include/replication/syncrep.h +++ b/src/include/replication/syncrep.h @@ -3,9 +3,10 @@ * syncrep.h * Exports from replication/syncrep.c. * - * Portions Copyright (c) 2010-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2011, PostgreSQL Global Development Group * - * $PostgreSQL$ + * IDENTIFICATION + * src/include/replication/syncrep.h * *------------------------------------------------------------------------- */ @@ -18,7 +19,8 @@ #include "storage/spin.h" #include "utils/guc.h" -#define SyncRepRequested() (sync_rep_mode) +#define SyncRepRequested() \ + (synchronous_replication && max_wal_senders > 0) /* syncRepState */ #define SYNC_REP_NOT_WAITING 0 @@ -27,8 +29,7 @@ #define SYNC_REP_MUST_DISCONNECT 3 /* user-settable parameters for synchronous replication */ -extern bool sync_rep_mode; -extern int sync_rep_timeout; +extern bool synchronous_replication; extern char *SyncRepStandbyNames; /* called by user backend */ @@ -43,6 +44,6 @@ extern void SyncRepReleaseWaiters(void); /* called by various procs */ extern int SyncRepWakeQueue(bool all); -const char *assign_synchronous_standby_names(const char *newval, bool doit, GucSource source); +extern const char *assign_synchronous_standby_names(const char *newval, bool doit, GucSource source); #endif /* _SYNCREP_H */ diff --git a/src/include/replication/walsender.h b/src/include/replication/walsender.h index 8a8c9398d1..2e5b2096ea 100644 --- a/src/include/replication/walsender.h +++ b/src/include/replication/walsender.h @@ -74,8 +74,7 @@ typedef struct /* * Current location of the head of the queue. All waiters should have - * a waitLSN that follows this value, or they are currently being woken - * to remove themselves from the queue. Protected by SyncRepLock. + * a waitLSN that follows this value. Protected by SyncRepLock. */ XLogRecPtr lsn; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 1d6642c6c7..f2e063c6cb 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -122,7 +122,7 @@ struct PGPROC * Info to allow us to wait for synchronous replication, if needed. * waitLSN is InvalidXLogRecPtr if not waiting; set only by user backend. * syncRepState must not be touched except by owning process or WALSender. - * syncRep_links used only while holding SyncRepLock. + * syncRepLinks used only while holding SyncRepLock. */ Latch waitLatch; /* allow us to wait for sync rep */ XLogRecPtr waitLSN; /* waiting for this LSN or higher */ diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index c0f7b64d80..e96323efcc 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -317,5 +317,6 @@ extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid); extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid); extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid); extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid); +extern bool has_createrole_privilege(Oid roleid); #endif /* ACL_H */ diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index d2b3862ec7..41188a2369 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1565,7 +1565,7 @@ plpgsql_parse_wordtype(char *ident) * Word wasn't found in the namespace stack. Try to find a data type with * that name, but ignore shell types and complex types. */ - typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, NULL); + typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL); if (typeTup) { Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile index 82ce248a07..0f709a1e3c 100644 --- a/src/test/isolation/Makefile +++ b/src/test/isolation/Makefile @@ -29,7 +29,7 @@ all: isolationtester pg_isolation_regress isolationtester: $(OBJS) | submake-libpq submake-libpgport $(CC) $(CFLAGS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) -distprep: specparse.c +distprep: specparse.c specscanner.c # There is no correct way to write a rule that generates two files. # Rules with two targets don't have that meaning, they are merely @@ -58,7 +58,9 @@ ifdef FLEX else @$(missing) flex $< $@ endif -# specparse.c is in the distribution tarball, so is not cleaned here + +# specparse.c and specscanner.c are in the distribution tarball, +# so do not clean them here clean distclean: rm -f isolationtester$(X) pg_isolation_regress$(X) $(OBJS) isolation_main.o rm -f pg_regress.o diff --git a/src/test/isolation/isolationtester.h b/src/test/isolation/isolationtester.h index b092ed16a0..1f86db8727 100644 --- a/src/test/isolation/isolationtester.h +++ b/src/test/isolation/isolationtester.h @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * - * bootstrap.h - * include file for the bootstrapping code + * isolationtester.h + * include file for isolation tests * - * - * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.44 2006/10/04 00:30:07 momjian Exp $ + * IDENTIFICATION + * src/test/isolation/isolationtester.h * *------------------------------------------------------------------------- */ diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l index 6752aca82d..c3193917c0 100644 --- a/src/test/isolation/specscanner.l +++ b/src/test/isolation/specscanner.l @@ -32,10 +32,9 @@ static void addlitchar(const char c); %x qstr non_newline [^\n\r] -space [ \t\n\r\f] +space [ \t\r\f] comment ("#"{non_newline}*) -whitespace ({space}+|{comment}) %% @@ -46,10 +45,10 @@ step { return(STEP); } teardown { return(TEARDOWN); } [\n] { yyline++; } -{whitespace} { - /* ignore */ - } +{comment} { /* ignore */ } +{space} { /* ignore */ } + /* Quoted strings: "foo" */ \" { litbufpos = 0; BEGIN(qstr); @@ -61,27 +60,36 @@ teardown { return(TEARDOWN); } return(string); } <qstr>. { addlitchar(yytext[0]); } +<qstr>\n { yyerror("unexpected newline in quoted string"); } +<qstr><<EOF>> { yyerror("unterminated quoted string"); } + /* SQL blocks: { UPDATE ... } */ "{" { litbufpos = 0; BEGIN(sql); } - <sql>"}" { litbuf[litbufpos] = '\0'; yylval.str = strdup(litbuf); BEGIN(INITIAL); return(sqlblock); } -<sql>[^}] { addlitchar(yytext[0]);} - +<sql>. { + addlitchar(yytext[0]); + } +<sql>\n { + yyline++; + addlitchar(yytext[0]); + } +<sql><<EOF>> { + yyerror("unterminated sql block"); + } . { fprintf(stderr, "syntax error at line %d: unexpected character \"%s\"\n", yyline, yytext); exit(1); } - %% static void diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out index caa65b2f37..5ad5de2f00 100644 --- a/src/test/regress/expected/collate.linux.utf8.out +++ b/src/test/regress/expected/collate.linux.utf8.out @@ -20,21 +20,21 @@ CREATE TABLE collate_test_fail ( ); ERROR: collation "ja_JP.eucjp" for current database encoding "UTF8" does not exist LINE 3: b text COLLATE "ja_JP.eucjp" - ^ + ^ CREATE TABLE collate_test_fail ( a int, b text COLLATE "foo" ); ERROR: collation "foo" for current database encoding "UTF8" does not exist LINE 3: b text COLLATE "foo" - ^ + ^ CREATE TABLE collate_test_fail ( a int COLLATE "en_US.utf8", b text ); ERROR: collations are not supported by type integer LINE 2: a int COLLATE "en_US.utf8", - ^ + ^ CREATE TABLE collate_test_like ( LIKE collate_test1 ); @@ -632,9 +632,9 @@ ERROR: no collation was derived for column "b" with collatable type text HINT: Use the COLLATE clause to set the collation explicitly. -- casting SELECT CAST('42' AS text COLLATE "C"); -ERROR: COLLATE clause not allowed in cast target +ERROR: syntax error at or near "COLLATE" LINE 1: SELECT CAST('42' AS text COLLATE "C"); - ^ + ^ SELECT a, CAST(b AS varchar) FROM collate_test1 ORDER BY 2; a | b ---+----- @@ -727,6 +727,8 @@ CREATE INDEX collate_test1_idx4 ON collate_test1 (a COLLATE "C"); -- fail ERROR: collations are not supported by type integer CREATE INDEX collate_test1_idx5 ON collate_test1 ((a COLLATE "C")); -- fail ERROR: collations are not supported by type integer +LINE 1: ...ATE INDEX collate_test1_idx5 ON collate_test1 ((a COLLATE "C... + ^ SELECT relname, pg_get_indexdef(oid) FROM pg_class WHERE relname LIKE 'collate_test%_idx%'; relname | pg_get_indexdef --------------------+---------------------------------------------------------------------------------------------- diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index 00730f25cb..a7473349fd 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -693,7 +693,7 @@ ERROR: "ft1" is not a table or view ALTER FOREIGN TABLE ft1 ALTER COLUMN c6 SET NOT NULL; ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL; ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR -ERROR: ALTER TYPE USING is not supported on foreign tables +ERROR: ALTER TYPE USING is only supported on plain tables ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10); ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text; -- can't change the column type if it's used elsewhere diff --git a/src/tools/git-external-diff b/src/tools/git-external-diff new file mode 100644 index 0000000000..fdc7080f3a --- /dev/null +++ b/src/tools/git-external-diff @@ -0,0 +1,22 @@ +#!/bin/bash + +# Parameters: +# $1 $2 $3 $4 $5 $6 $7 +# path old-file old-hash old-mode new-file new-hash new-mode +# 'path' is the git-tree-relative path of the file being diff'ed + +old_hash="$3" +new_hash=$(git hash-object "$5") + +# no change? +[ "$old_hash" = "$new_hash" ] && exit 0 + +[ "$DIFF_OPTS" = "" ] && DIFF_OPTS='-pcd' + +echo "diff --git a/$1 b/$1" +echo "new file mode $7" +echo "index ${old_hash:0:7}..${new_hash:0:7}" + +diff --label a/"$1" --label b/"$1" $DIFF_OPTS "$2" "$5" + +exit 0 |