diff --git a/COPYRIGHT b/COPYRIGHT index 0a397648dcd3c..55e5af80623a4 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,15 @@ -PostgreSQL Database Management System +Percona Server for PostgreSQL - License (also known as Postgres, formerly known as Postgres95) +This software includes portions copyrighted or made available by: +• Percona, LLC and/or its affiliates (collectively, "Percona") +• PostgreSQL Global Development Group ("PostgreSQL") +• The Regents of the University of California + +A. PostgreSQL and University of California Portions. Those portions of this Software +copyrighted or made available by PostgreSQL or The Regents of the University of +California are subject to the following: + Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California @@ -12,12 +21,32 @@ paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING -LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS -DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS -ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO -PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, +EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, +AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, +SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +B. Percona Portions. Those portions of this Software copyrighted or made available +by Percona are subject both to the disclaimers in part A of this license and the following: + +Copyright (c) 2024-2025, Percona LLC and/or its affiliates + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL PERCONA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, +INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE +USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF PERCONA HAS BEEN ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +PERCONA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND PERCONA HAS NO +OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/README.md b/README.md index 7352a90a72373..8071afd49d9b6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -PostgreSQL Database Management System -===================================== +Percona Server for PostgreSQL +============================= -This directory contains the source code distribution of the PostgreSQL -database management system. +Percona Server for PostgreSQL is a free, enhanced, fully compatible, +open source, drop-in replacement for the PostgreSQL Database Management +System with enterprise-grade features. +It requires no changes to PostgreSQL applications or code. PostgreSQL is an advanced object-relational database management system that supports an extended subset of the SQL standard, including @@ -11,11 +13,24 @@ and functions. This distribution also contains C language bindings. Copyright and license information can be found in the file COPYRIGHT. -General documentation about this version of PostgreSQL can be found at -. In particular, information +General documentation about this version of Percona Server for PostgreSQL can be found at +[https://docs.percona.com/postgresql/18/](https://docs.percona.com/postgresql/18/). In particular, information about building PostgreSQL from the source code can be found at -. +[https://docs.percona.com/postgresql/18/installing.html](https://docs.percona.com/postgresql/18/installing.html). + +Submit a bug report or a feature request +--- + +If you find a bug in Percona Server for PostgreSQL, you can submit a report to the project's +[Jira](https://perconadev.atlassian.net/jira/software/c/projects/PG/issues) issue tracker + +As a general rule of thumb, please try to create a bug report that is: + +Reproducible - include the steps on how to reproduce the issue + +Specific - include as much detail as possible, such as which version, which environment, etc. + +Unique - do not duplicate existing tickets + +Scoped to a single issue - only one issue per report -The latest version of this software, and related software, may be -obtained at . For more information -look at our web site located at . diff --git a/config/llvm.m4 b/config/llvm.m4 index 9d6fe8199e364..d4524c854656d 100644 --- a/config/llvm.m4 +++ b/config/llvm.m4 @@ -47,20 +47,20 @@ AC_DEFUN([PGAC_LLVM_SUPPORT], # Collect compiler flags necessary to build the LLVM dependent # shared library. - for pgac_option in `$LLVM_CONFIG --cppflags`; do + for pgac_option in `$LLVM_CONFIG --link-static --cppflags`; do case $pgac_option in -I*|-D*) LLVM_CPPFLAGS="$pgac_option $LLVM_CPPFLAGS";; esac done - for pgac_option in `$LLVM_CONFIG --ldflags`; do + for pgac_option in `$LLVM_CONFIG --link-static --ldflags`; do case $pgac_option in -L*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac done # ABI influencing options, standard influencing options - for pgac_option in `$LLVM_CONFIG --cxxflags`; do + for pgac_option in `$LLVM_CONFIG --link-static --cxxflags`; do case $pgac_option in -fno-rtti*) LLVM_CXXFLAGS="$LLVM_CXXFLAGS $pgac_option";; -std=*) LLVM_CXXFLAGS="$LLVM_CXXFLAGS $pgac_option";; @@ -71,7 +71,7 @@ AC_DEFUN([PGAC_LLVM_SUPPORT], # libs. As some components are optional, we can't just list all of # them as it'd raise an error. pgac_components=''; - for pgac_component in `$LLVM_CONFIG --components`; do + for pgac_component in `$LLVM_CONFIG --link-static --components`; do case $pgac_component in engine) pgac_components="$pgac_components $pgac_component";; debuginfodwarf) pgac_components="$pgac_components $pgac_component";; @@ -85,7 +85,7 @@ AC_DEFUN([PGAC_LLVM_SUPPORT], # And then get the libraries that need to be linked in for the # selected components. They're large libraries, we only want to # link them into the LLVM using shared library. - for pgac_option in `$LLVM_CONFIG --libs --system-libs $pgac_components`; do + for pgac_option in `$LLVM_CONFIG --link-static --libs --system-libs $pgac_components`; do case $pgac_option in -l*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac diff --git a/configure b/configure index 540f911863fb1..1cd9176ed6a85 100755 --- a/configure +++ b/configure @@ -2885,6 +2885,13 @@ cat >>confdefs.h <<_ACEOF _ACEOF +PG_PERCONAVERSION=1 + +cat >>confdefs.h <<_ACEOF +#define PG_PERCONAVERSION "$PG_PERCONAVERSION" +_ACEOF + + @@ -2899,12 +2906,12 @@ if test "${with_extra_version+set}" = set; then : as_fn_error $? "argument required for --with-extra-version option" "$LINENO" 5 ;; *) - PG_VERSION="$PACKAGE_VERSION$withval" + PG_VERSION="$PACKAGE_VERSION - Percona Server for PostgreSQL $PG_MAJORVERSION.$PG_MINORVERSION.$PG_PERCONAVERSION$withval" ;; esac else - PG_VERSION="$PACKAGE_VERSION" + PG_VERSION="$PACKAGE_VERSION - Percona Server for PostgreSQL $PG_MAJORVERSION.$PG_MINORVERSION.$PG_PERCONAVERSION" fi @@ -5186,20 +5193,20 @@ fi # Collect compiler flags necessary to build the LLVM dependent # shared library. - for pgac_option in `$LLVM_CONFIG --cppflags`; do + for pgac_option in `$LLVM_CONFIG --link-static --cppflags`; do case $pgac_option in -I*|-D*) LLVM_CPPFLAGS="$pgac_option $LLVM_CPPFLAGS";; esac done - for pgac_option in `$LLVM_CONFIG --ldflags`; do + for pgac_option in `$LLVM_CONFIG --link-static --ldflags`; do case $pgac_option in -L*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac done # ABI influencing options, standard influencing options - for pgac_option in `$LLVM_CONFIG --cxxflags`; do + for pgac_option in `$LLVM_CONFIG --link-static --cxxflags`; do case $pgac_option in -fno-rtti*) LLVM_CXXFLAGS="$LLVM_CXXFLAGS $pgac_option";; -std=*) LLVM_CXXFLAGS="$LLVM_CXXFLAGS $pgac_option";; @@ -5210,7 +5217,7 @@ fi # libs. As some components are optional, we can't just list all of # them as it'd raise an error. pgac_components=''; - for pgac_component in `$LLVM_CONFIG --components`; do + for pgac_component in `$LLVM_CONFIG --link-static --components`; do case $pgac_component in engine) pgac_components="$pgac_components $pgac_component";; debuginfodwarf) pgac_components="$pgac_components $pgac_component";; @@ -5224,7 +5231,7 @@ fi # And then get the libraries that need to be linked in for the # selected components. They're large libraries, we only want to # link them into the LLVM using shared library. - for pgac_option in `$LLVM_CONFIG --libs --system-libs $pgac_components`; do + for pgac_option in `$LLVM_CONFIG --link-static --libs --system-libs $pgac_components`; do case $pgac_option in -l*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac diff --git a/configure.ac b/configure.ac index 6007f573561e5..a33a8cfa3eb2b 100644 --- a/configure.ac +++ b/configure.ac @@ -37,9 +37,12 @@ AC_DEFINE_UNQUOTED(PG_MAJORVERSION, "$PG_MAJORVERSION", [PostgreSQL major versio AC_DEFINE_UNQUOTED(PG_MAJORVERSION_NUM, $PG_MAJORVERSION, [PostgreSQL major version number]) AC_DEFINE_UNQUOTED(PG_MINORVERSION_NUM, $PG_MINORVERSION, [PostgreSQL minor version number]) +[PG_PERCONAVERSION=1] +AC_DEFINE_UNQUOTED(PG_PERCONAVERSION, "$PG_PERCONAVERSION", [PostgreSQL Percona version as a string]) + PGAC_ARG_REQ(with, extra-version, [STRING], [append STRING to version], - [PG_VERSION="$PACKAGE_VERSION$withval"], - [PG_VERSION="$PACKAGE_VERSION"]) + [PG_VERSION="$PACKAGE_VERSION - Percona Server for PostgreSQL $PG_MAJORVERSION.$PG_MINORVERSION.$PG_PERCONAVERSION$withval"], + [PG_VERSION="$PACKAGE_VERSION - Percona Server for PostgreSQL $PG_MAJORVERSION.$PG_MINORVERSION.$PG_PERCONAVERSION"]) AC_DEFINE_UNQUOTED(PG_VERSION, "$PG_VERSION", [PostgreSQL version as a string]) AC_CANONICAL_HOST diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c index aa9cccd1da4fe..64638ea65fb40 100644 --- a/contrib/amcheck/verify_heapam.c +++ b/contrib/amcheck/verify_heapam.c @@ -16,6 +16,7 @@ #include "access/multixact.h" #include "access/relation.h" #include "access/table.h" +#include "access/tableam.h" #include "access/toast_internals.h" #include "access/visibilitymap.h" #include "access/xact.h" @@ -343,7 +344,7 @@ verify_heapam(PG_FUNCTION_ARGS) * Other relkinds might be using a different AM, so check. */ if (ctx.rel->rd_rel->relkind != RELKIND_SEQUENCE && - ctx.rel->rd_rel->relam != HEAP_TABLE_AM_OID) + ctx.rel->rd_tableam != GetHeapamTableAmRoutine()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("only heap AM is supported"))); diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c index e58f5f9cdf775..2e24d564d983f 100644 --- a/contrib/pageinspect/heapfuncs.c +++ b/contrib/pageinspect/heapfuncs.c @@ -27,6 +27,7 @@ #include "access/htup_details.h" #include "access/relation.h" +#include "access/tableam.h" #include "catalog/pg_am_d.h" #include "catalog/pg_type.h" #include "funcapi.h" @@ -333,7 +334,7 @@ tuple_data_split_internal(Oid relid, char *tupdata, * Sequences always use heap AM, but they don't show that in the catalogs. */ if (rel->rd_rel->relkind != RELKIND_SEQUENCE && - rel->rd_rel->relam != HEAP_TABLE_AM_OID) + rel->rd_tableam != GetHeapamTableAmRoutine()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("only heap AM is supported"))); diff --git a/contrib/pg_surgery/heap_surgery.c b/contrib/pg_surgery/heap_surgery.c index 3e86283beb7cf..40a0147edd462 100644 --- a/contrib/pg_surgery/heap_surgery.c +++ b/contrib/pg_surgery/heap_surgery.c @@ -14,6 +14,7 @@ #include "access/htup_details.h" #include "access/relation.h" +#include "access/tableam.h" #include "access/visibilitymap.h" #include "access/xloginsert.h" #include "catalog/pg_am_d.h" @@ -115,7 +116,7 @@ heap_force_common(FunctionCallInfo fcinfo, HeapTupleForceOption heap_force_opt) RelationGetRelationName(rel)), errdetail_relkind_not_supported(rel->rd_rel->relkind))); - if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) + if (rel->rd_tableam != GetHeapamTableAmRoutine()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("only heap AM is supported"))); diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c index b75d80fa7a9c2..579b87a15a0c7 100644 --- a/contrib/pgrowlocks/pgrowlocks.c +++ b/contrib/pgrowlocks/pgrowlocks.c @@ -95,7 +95,7 @@ pgrowlocks(PG_FUNCTION_ARGS) (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", RelationGetRelationName(rel)))); - else if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) + else if (rel->rd_tableam != GetHeapamTableAmRoutine()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("only heap AM is supported"))); diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index a59ff4e9d4fac..94138b10282fc 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -280,7 +280,7 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo) RelationGetRelationName(rel)), errdetail_relkind_not_supported(rel->rd_rel->relkind))); - if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) + if (rel->rd_tableam != GetHeapamTableAmRoutine()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("only heap AM is supported"))); diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index dbe7a190aaf6d..5b6f0f9b212ef 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -329,7 +329,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo) * Sequences always use heap AM, but they don't show that in the catalogs. */ if (rel->rd_rel->relkind != RELKIND_SEQUENCE && - rel->rd_rel->relam != HEAP_TABLE_AM_OID) + rel->rd_tableam != GetHeapamTableAmRoutine()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("only heap AM is supported"))); diff --git a/meson.build b/meson.build index 34456b36bbf29..9629cb2fb6874 100644 --- a/meson.build +++ b/meson.build @@ -135,6 +135,7 @@ endif pg_version_major = pg_version_arr[0].to_int() pg_version_minor = pg_version_arr[1].to_int() pg_version_num = (pg_version_major * 10000) + pg_version_minor +pg_percona_ver = '1' pg_url = 'https://www.postgresql.org/' @@ -145,6 +146,7 @@ cdata.set_quoted('PACKAGE_VERSION', pg_version) cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version)) cdata.set_quoted('PACKAGE_TARNAME', 'postgresql') +pg_version += ' - Percona Server for PostgreSQL ' + pg_version_major.to_string() + '.' + pg_version_minor.to_string() + '.' + pg_percona_ver pg_version += get_option('extra_version') cdata.set_quoted('PG_VERSION', pg_version) cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string()) @@ -808,7 +810,7 @@ endif llvmopt = get_option('llvm') llvm = not_found_dep if add_languages('cpp', required: llvmopt, native: false) - llvm = dependency('llvm', version: '>=14', method: 'config-tool', required: llvmopt) + llvm = dependency('llvm', version: '>=14', method: 'config-tool', required: llvmopt, static: true) if llvm.found() diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index cb4bc35c93ed4..677d5d38bb63e 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -588,6 +588,8 @@ heapam_relation_set_new_filelocator(Relation rel, { SMgrRelation srel; + RelFileLocator oldlocator = rel->rd_locator; + /* * Initialize to the minimum XID that could put tuples in the table. We * know that no xacts older than RecentXmin are still running, so that @@ -605,7 +607,7 @@ heapam_relation_set_new_filelocator(Relation rel, */ *minmulti = GetOldestMultiXactId(); - srel = RelationCreateStorage(*newrlocator, persistence, true); + srel = RelationCreateStorage2(oldlocator, *newrlocator, persistence, true); /* * If required, set up an init fork for an unlogged table so that it can @@ -615,7 +617,7 @@ heapam_relation_set_new_filelocator(Relation rel, { Assert(rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_TOASTVALUE); - smgrcreate(srel, INIT_FORKNUM, false); + smgrcreate2(oldlocator, srel, INIT_FORKNUM, false); log_smgrcreate(newrlocator, INIT_FORKNUM); } @@ -648,7 +650,7 @@ heapam_relation_copy_data(Relation rel, const RelFileLocator *newrlocator) * NOTE: any conflict in relfilenumber value will be caught in * RelationCreateStorage(). */ - dstrel = RelationCreateStorage(*newrlocator, rel->rd_rel->relpersistence, true); + dstrel = RelationCreateStorage2(rel->rd_locator, *newrlocator, rel->rd_rel->relpersistence, true); /* copy main fork */ RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM, @@ -660,7 +662,7 @@ heapam_relation_copy_data(Relation rel, const RelFileLocator *newrlocator) { if (smgrexists(RelationGetSmgr(rel), forkNum)) { - smgrcreate(dstrel, forkNum, false); + smgrcreate2(rel->rd_locator, dstrel, forkNum, false); /* * WAL log creation if the relation is persistent, or this is the diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index d03db6b1f85cd..ff5160c994086 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -61,6 +61,7 @@ #include "access/xloginsert.h" #include "access/xlogreader.h" #include "access/xlogrecovery.h" +#include "access/xlog_smgr.h" #include "access/xlogutils.h" #include "backup/basebackup.h" #include "catalog/catversion.h" @@ -2431,7 +2432,7 @@ XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible) start = pgstat_prepare_io_time(track_wal_io_timing); pgstat_report_wait_start(WAIT_EVENT_WAL_WRITE); - written = pg_pwrite(openLogFile, from, nleft, startoffset); + written = xlog_smgr->seg_write(openLogFile, from, nleft, startoffset, tli, openLogSegNo, wal_segment_size); pgstat_report_wait_end(); pgstat_count_io_op_time(IOOBJECT_WAL, IOCONTEXT_NORMAL, @@ -3421,6 +3422,7 @@ XLogFileCopy(TimeLineID destTLI, XLogSegNo destsegno, int srcfd; int fd; int nbytes; + off_t offset = 0; /* * Open the source file @@ -3469,7 +3471,8 @@ XLogFileCopy(TimeLineID destTLI, XLogSegNo destsegno, if (nread > sizeof(buffer)) nread = sizeof(buffer); pgstat_report_wait_start(WAIT_EVENT_WAL_COPY_READ); - r = read(srcfd, buffer.data, nread); + r = xlog_smgr->seg_read(srcfd, buffer.data, nread, offset, + srcTLI, srcsegno, wal_segment_size); if (r != nread) { if (r < 0) @@ -3487,7 +3490,7 @@ XLogFileCopy(TimeLineID destTLI, XLogSegNo destsegno, } errno = 0; pgstat_report_wait_start(WAIT_EVENT_WAL_COPY_WRITE); - if ((int) write(fd, buffer.data, sizeof(buffer)) != (int) sizeof(buffer)) + if ((int) xlog_smgr->seg_write(fd, buffer.data, sizeof(buffer), offset, destTLI, destsegno, wal_segment_size) != (int) sizeof(buffer)) { int save_errno = errno; @@ -3503,6 +3506,7 @@ XLogFileCopy(TimeLineID destTLI, XLogSegNo destsegno, errmsg("could not write to file \"%s\": %m", tmppath))); } pgstat_report_wait_end(); + offset += sizeof(buffer); } pgstat_report_wait_start(WAIT_EVENT_WAL_COPY_SYNC); diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index 5c26d33a60380..f5cfccb684ba8 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -29,6 +29,7 @@ #include "access/xlog_internal.h" #include "access/xlogreader.h" #include "access/xlogrecord.h" +#include "access/xlog_smgr.h" #include "catalog/pg_control.h" #include "common/pg_lzcompress.h" #include "replication/origin.h" @@ -64,6 +65,21 @@ static void WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt, */ #define DEFAULT_DECODE_BUFFER_SIZE (64 * 1024) +/* + * XLog storage manager + * + * TODO: should be in xlog.c or new xlog_smgr.c ? + * Now it's here because pg_rewind and other tools compile only + * w/ xlogreader.c + */ +const XLogSmgr *xlog_smgr = &xlog_smgr_standard; + +void +SetXLogSmgr(const XLogSmgr *xlsmgr) +{ + xlog_smgr = xlsmgr; +} + /* * Construct a string in state->errormsg_buf explaining what's wrong with * the current record being read. @@ -1574,7 +1590,9 @@ WALRead(XLogReaderState *state, /* Reset errno first; eases reporting non-errno-affecting errors */ errno = 0; - readbytes = pg_pread(state->seg.ws_file, p, segbytes, (off_t) startoff); + readbytes = xlog_smgr->seg_read(state->seg.ws_file, p, segbytes, + (off_t) startoff, state->seg.ws_tli, + state->seg.ws_segno, state->segcxt.ws_segsize); #ifndef FRONTEND pgstat_report_wait_end(); diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index ff4d9edc7900f..7cd21cf37cf76 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -39,6 +39,7 @@ #include "access/xlogprefetcher.h" #include "access/xlogreader.h" #include "access/xlogrecovery.h" +#include "access/xlog_smgr.h" #include "access/xlogutils.h" #include "backup/basebackup.h" #include "catalog/pg_control.h" @@ -3423,7 +3424,8 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, io_start = pgstat_prepare_io_time(track_wal_io_timing); pgstat_report_wait_start(WAIT_EVENT_WAL_READ); - r = pg_pread(readFile, readBuf, XLOG_BLCKSZ, (off_t) readOff); + r = xlog_smgr->seg_read(readFile, readBuf, XLOG_BLCKSZ, (off_t) readOff, + curFileTLI, readSegNo, wal_segment_size); if (r != XLOG_BLCKSZ) { char fname[MAXFNAMELEN]; diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index c389b27f77d47..ec5d993172530 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -487,7 +487,7 @@ XLogReadBufferExtended(RelFileLocator rlocator, ForkNumber forknum, * filesystem loses an inode during a crash. Better to write the data * until we are actually told to delete the file.) */ - smgrcreate(smgr, forknum, true); + smgrcreate2(rlocator, smgr, forknum, true); lastblock = smgrnblocks(smgr, forknum); diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 9833f52c1bed6..eedd006ecaa06 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -217,7 +217,8 @@ Boot_CreateStmt: true, &relfrozenxid, &relminmxid, - true); + true, + NULL); elog(DEBUG4, "bootstrap relation created"); } else diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 931010ea3d4fa..e777e0e27e206 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -296,7 +296,8 @@ heap_create(const char *relname, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, - bool create_storage) + bool create_storage, + RelFileLocator *old_rlocator) { Relation rel; @@ -381,14 +382,31 @@ heap_create(const char *relname, */ if (create_storage) { + RelFileLocator prev_rlocator = rel->rd_locator; + RelFileLocator new_rlocator = rel->rd_locator; + + if (old_rlocator != NULL) + { + prev_rlocator = *old_rlocator; + + /* + * table_relation_set_new_filelocator() takes old_rlocator from + * rel->rd_locator + */ + rel->rd_locator = prev_rlocator; + } + if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind)) - table_relation_set_new_filelocator(rel, &rel->rd_locator, + table_relation_set_new_filelocator(rel, &new_rlocator, relpersistence, relfrozenxid, relminmxid); else if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind)) - RelationCreateStorage(rel->rd_locator, relpersistence, true); + RelationCreateStorage2(prev_rlocator, new_rlocator, relpersistence, true); else Assert(false); + + /* restore the orginal rel's locator */ + rel->rd_locator = new_rlocator; } /* @@ -1147,6 +1165,8 @@ heap_create_with_catalog(const char *relname, Oid existing_relid; Oid old_type_oid; Oid new_type_oid; + RelFileLocator *old_rlocator = NULL; + Relation old_rel; /* By default set to InvalidOid unless overridden by binary-upgrade */ RelFileNumber relfilenumber = InvalidRelFileNumber; @@ -1301,6 +1321,12 @@ heap_create_with_catalog(const char *relname, else relacl = NULL; + if (relrewrite != InvalidOid) + { + old_rel = table_open(relrewrite, AccessShareLock); + old_rlocator = &old_rel->rd_locator; + } + /* * Create the relcache entry (mostly dummy at this point) and the physical * disk file. (If we fail further down, it's the smgr's responsibility to @@ -1324,7 +1350,11 @@ heap_create_with_catalog(const char *relname, allow_system_table_mods, &relfrozenxid, &relminmxid, - true); + true, + old_rlocator); + + if (relrewrite != InvalidOid) + table_close(old_rel, AccessShareLock); Assert(relid == RelationGetRelid(new_rel_desc)); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index aa216683b74fe..ff05dec3d9817 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -674,6 +674,35 @@ UpdateIndexRelation(Oid indexoid, heap_freetuple(tuple); } +extern Oid index_create(Relation heapRelation, + const char *indexRelationName, + Oid indexRelationId, + Oid parentIndexRelid, + Oid parentConstraintId, + RelFileNumber relFileNumber, + IndexInfo *indexInfo, + const List *indexColNames, + Oid accessMethodId, + Oid tableSpaceId, + const Oid *collationIds, + const Oid *opclassIds, + const Datum *opclassOptions, + const int16 *coloptions, + const NullableDatum *stattargets, + Datum reloptions, + bits16 flags, + bits16 constr_flags, + bool allow_system_table_mods, + bool is_internal, + Oid *constraintId) +{ + if(!allow_upstream_smgr_api) { + elog(FATAL, "An extension is trying to use the traditional index_create method, while another loaded extension (pg_tde) requires the new API."); + } + return index_create2(heapRelation, indexRelationName, indexRelationId, parentIndexRelid, parentConstraintId, relFileNumber, + indexInfo, indexColNames, accessMethodId, tableSpaceId, collationIds, opclassIds, opclassOptions, coloptions, stattargets, reloptions, + flags, constr_flags, allow_system_table_mods, is_internal, constraintId, NULL); +} /* * index_create @@ -723,7 +752,7 @@ UpdateIndexRelation(Oid indexoid, * Returns the OID of the created index. */ Oid -index_create(Relation heapRelation, +index_create2(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, @@ -743,7 +772,8 @@ index_create(Relation heapRelation, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, - Oid *constraintId) + Oid *constraintId, + RelFileLocator *old_rlocator) { Oid heapRelationId = RelationGetRelid(heapRelation); Relation pg_class; @@ -987,7 +1017,8 @@ index_create(Relation heapRelation, allow_system_table_mods, &relfrozenxid, &relminmxid, - create_storage); + create_storage, + old_rlocator); Assert(relfrozenxid == InvalidTransactionId); Assert(relminmxid == InvalidMultiXactId); @@ -1442,7 +1473,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, * ensure a consistent state at all times. That is why parentIndexRelid * is not set here. */ - newIndexId = index_create(heapRelation, + newIndexId = index_create2(heapRelation, newName, InvalidOid, /* indexRelationId */ InvalidOid, /* parentIndexRelid */ @@ -1462,7 +1493,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, 0, true, /* allow table to be a system catalog? */ false, /* is_internal? */ - NULL); + NULL, + &indexRelation->rd_locator); /* Close the relations used and clean up */ index_close(indexRelation, NoLock); @@ -3089,7 +3121,7 @@ index_build(Relation heapRelation, if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED && !smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM)) { - smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false); + smgrcreate2(indexRelation->rd_locator, RelationGetSmgr(indexRelation), INIT_FORKNUM, false); log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM); indexRelation->rd_indam->ambuildempty(indexRelation); } diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 85d1219b235fa..60204da3b58af 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -105,6 +105,16 @@ AddPendingSync(const RelFileLocator *rlocator) pending->is_truncated = false; } +extern SMgrRelation RelationCreateStorage(RelFileLocator rlocator, + char relpersistence, + bool register_delete) +{ + if(!allow_upstream_smgr_api) { + elog(FATAL, "An extension is trying to use the traditional RelationCreateStorage method, while another loaded extension (pg_tde) requires the new API."); + } + return RelationCreateStorage2(rlocator, rlocator, relpersistence, register_delete); +} + /* * RelationCreateStorage * Create physical storage for a relation. @@ -119,7 +129,7 @@ AddPendingSync(const RelFileLocator *rlocator) * pass register_delete = false. */ SMgrRelation -RelationCreateStorage(RelFileLocator rlocator, char relpersistence, +RelationCreateStorage2(RelFileLocator oldlocator, RelFileLocator rlocator, char relpersistence, bool register_delete) { SMgrRelation srel; @@ -148,7 +158,7 @@ RelationCreateStorage(RelFileLocator rlocator, char relpersistence, } srel = smgropen(rlocator, procNumber); - smgrcreate(srel, MAIN_FORKNUM, false); + smgrcreate2(oldlocator, srel, MAIN_FORKNUM, false); if (needs_wal) log_smgrcreate(&srel->smgr_rlocator.locator, MAIN_FORKNUM); @@ -992,7 +1002,7 @@ smgr_redo(XLogReaderState *record) SMgrRelation reln; reln = smgropen(xlrec->rlocator, INVALID_PROC_NUMBER); - smgrcreate(reln, xlrec->forkNum, true); + smgrcreate2(xlrec->rlocator, reln, xlrec->forkNum, true); } else if (info == XLOG_SMGR_TRUNCATE) { @@ -1013,7 +1023,7 @@ smgr_redo(XLogReaderState *record) * XLogReadBufferForRedo, we prefer to recreate the rel and replay the * log as best we can until the drop is seen. */ - smgrcreate(reln, MAIN_FORKNUM, true); + smgrcreate2(xlrec->rlocator, reln, MAIN_FORKNUM, true); /* * Before we perform the truncation, update minimum recovery point to diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 874a8fc89adb3..087fac348bcea 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -318,14 +318,14 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, coloptions[0] = 0; coloptions[1] = 0; - index_create(toast_rel, toast_idxname, toastIndexOid, InvalidOid, + index_create2(toast_rel, toast_idxname, toastIndexOid, InvalidOid, InvalidOid, InvalidOid, indexInfo, list_make2("chunk_id", "chunk_seq"), BTREE_AM_OID, rel->rd_rel->reltablespace, collationIds, opclassIds, NULL, coloptions, NULL, (Datum) 0, - INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL); + INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL, NULL); table_close(toast_rel, NoLock); diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 14679ff637370..95da018c773b7 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1243,7 +1243,7 @@ DefineIndex(Oid tableId, constr_flags |= INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS; indexRelationId = - index_create(rel, indexRelationName, indexRelationId, parentIndexId, + index_create2(rel, indexRelationName, indexRelationId, parentIndexId, parentConstraintId, stmt->oldNumber, indexInfo, indexColNames, accessMethodId, tablespaceId, @@ -1251,7 +1251,7 @@ DefineIndex(Oid tableId, coloptions, NULL, reloptions, flags, constr_flags, allowSystemTableMods, !check_rights, - &createdConstraintId); + &createdConstraintId, NULL); ObjectAddressSet(address, RelationRelationId, indexRelationId); diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index a79ef0651a9e0..18cc9762b04a0 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -344,7 +344,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple) SMgrRelation srel; srel = smgropen(rel->rd_locator, INVALID_PROC_NUMBER); - smgrcreate(srel, INIT_FORKNUM, false); + smgrcreate2(rel->rd_locator, srel, INIT_FORKNUM, false); log_smgrcreate(&rel->rd_locator, INIT_FORKNUM); fill_seq_fork_with_data(rel, tuple, INIT_FORKNUM); FlushRelationBuffers(rel); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index dd2b4a5107663..2046c45968d76 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -17163,7 +17163,7 @@ index_copy_data(Relation rel, RelFileLocator newrlocator) * NOTE: any conflict in relfilenumber value will be caught in * RelationCreateStorage(). */ - dstrel = RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true); + dstrel = RelationCreateStorage2(rel->rd_locator, newrlocator, rel->rd_rel->relpersistence, true); /* copy main fork */ RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM, @@ -17175,7 +17175,7 @@ index_copy_data(Relation rel, RelFileLocator newrlocator) { if (smgrexists(RelationGetSmgr(rel), forkNum)) { - smgrcreate(dstrel, forkNum, false); + smgrcreate2(rel->rd_locator, dstrel, forkNum, false); /* * WAL log creation if the relation is persistent, or this is the diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index e01d9f0cfe81e..58f8790230a5b 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -926,6 +926,11 @@ PostmasterMain(int argc, char *argv[]) */ ApplyLauncherRegister(); + /* + * Register built-in managers that are not part of static arrays + */ + register_builtin_dynamic_managers(); + /* * process any libraries that should be preloaded at postmaster start */ diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 8c4d0fd9aed2b..f4aeccc982ff1 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -57,6 +57,7 @@ #include "access/xlog_internal.h" #include "access/xlogarchive.h" #include "access/xlogrecovery.h" +#include "access/xlog_smgr.h" #include "catalog/pg_authid.h" #include "funcapi.h" #include "libpq/pqformat.h" @@ -928,7 +929,9 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr, TimeLineID tli) start = pgstat_prepare_io_time(track_wal_io_timing); pgstat_report_wait_start(WAIT_EVENT_WAL_WRITE); - byteswritten = pg_pwrite(recvFile, buf, segbytes, (off_t) startoff); + byteswritten = xlog_smgr->seg_write(recvFile, buf, segbytes, + (off_t) startoff, recvFileTLI, + recvSegNo, wal_segment_size); pgstat_report_wait_end(); pgstat_count_io_op_time(IOOBJECT_WAL, IOCONTEXT_NORMAL, diff --git a/src/backend/storage/aio/aio_callback.c b/src/backend/storage/aio/aio_callback.c index 03c9bba080267..594d30f421adb 100644 --- a/src/backend/storage/aio/aio_callback.c +++ b/src/backend/storage/aio/aio_callback.c @@ -27,8 +27,8 @@ static const PgAioHandleCallbacks aio_invalid_cb = {0}; typedef struct PgAioHandleCallbacksEntry { - const PgAioHandleCallbacks *const cb; - const char *const name; + const PgAioHandleCallbacks *cb; + const char *name; } PgAioHandleCallbacksEntry; /* @@ -36,7 +36,7 @@ typedef struct PgAioHandleCallbacksEntry * handle. See PgAioHandleCallbackID's definition for an explanation for why * callbacks are not identified by a pointer. */ -static const PgAioHandleCallbacksEntry aio_handle_cbs[] = { +static PgAioHandleCallbacksEntry aio_handle_cbs[PGAIO_HCB_MAX] = { #define CALLBACK_ENTRY(id, callback) [id] = {.cb = &callback, .name = #callback} CALLBACK_ENTRY(PGAIO_HCB_INVALID, aio_invalid_cb), @@ -48,7 +48,21 @@ static const PgAioHandleCallbacksEntry aio_handle_cbs[] = { #undef CALLBACK_ENTRY }; +static PgAioHandleCallbackID aio_handle_max_cb_id = PGAIO_HCB_LOCAL_BUFFER_READV; +PgAioHandleCallbackID +pgaio_io_register_callback_entry(const PgAioHandleCallbacks *callback, const char *name) +{ + PgAioHandleCallbackID cb_id = ++aio_handle_max_cb_id; + + if (cb_id > PGAIO_HCB_MAX) + elog(FATAL, "There can be at most %d AIO callback entries", PGAIO_HCB_MAX); + + aio_handle_cbs[cb_id].cb = callback; + aio_handle_cbs[cb_id].name = name; + + return cb_id; +} /* -------------------------------------------------------------------------------- * Public callback related functions operating on IO Handles diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 6ba5e2075341f..3e2f975a75032 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -955,7 +955,7 @@ ExtendBufferedRelTo(BufferManagerRelation bmr, /* recheck, fork might have been created concurrently */ if (!smgrexists(bmr.smgr, fork)) - smgrcreate(bmr.smgr, fork, flags & EB_PERFORMING_RECOVERY); + smgrcreate2(bmr.rel->rd_locator, bmr.smgr, fork, flags & EB_PERFORMING_RECOVERY); UnlockRelationForExtension(bmr.rel, ExclusiveLock); } @@ -5257,7 +5257,7 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator, * directory. Therefore, each individual relation doesn't need to be * registered for cleanup. */ - RelationCreateStorage(dst_rlocator, relpersistence, false); + RelationCreateStorage2(src_rlocator, dst_rlocator, relpersistence, false); /* copy main fork. */ RelationCopyStorageUsingBuffer(src_rlocator, dst_rlocator, MAIN_FORKNUM, @@ -5269,7 +5269,8 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator, { if (smgrexists(src_rel, forkNum)) { - smgrcreate(dst_rel, forkNum, false); + /* TODO: for sure? */ + smgrcreate2(src_rel->smgr_rlocator.locator, dst_rel, forkNum, false); /* * WAL log creation if the relation is persistent, or this is the diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index db4595d4d9d66..ae3ed6a457caa 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -85,6 +85,21 @@ typedef struct _MdfdVec } MdfdVec; static MemoryContext MdCxt; /* context for all MdfdVec objects */ +SMgrId MdSMgrId; + +typedef struct +{ + SMgrRelationData reln; /* parent data */ + + /* + * for md.c; per-fork arrays of the number of open segments + * (md_num_open_segs) and the segments themselves (md_seg_fds). + */ + int md_num_open_segs[MAX_FORKNUM + 1]; + MdfdVec *md_seg_fds[MAX_FORKNUM + 1]; +} MdSMgrRelationData; + +typedef MdSMgrRelationData *MdSMgrRelation; /* Populate a file tag describing an md.c segment file. */ @@ -131,32 +146,62 @@ typedef struct MdPathStr } MdPathStr; +void +mdsmgr_register(void) +{ + /* magnetic disk */ + f_smgr md_smgr = (f_smgr) { + .name = "md", + .smgr_init = mdinit, + .smgr_shutdown = NULL, + .smgr_open = mdopen, + .smgr_close = mdclose, + .smgr_create = mdcreate, + .smgr_exists = mdexists, + .smgr_unlink = mdunlink, + .smgr_extend = mdextend, + .smgr_zeroextend = mdzeroextend, + .smgr_prefetch = mdprefetch, + .smgr_maxcombine = mdmaxcombine, + .smgr_readv = mdreadv, + .smgr_startreadv = mdstartreadv, + .smgr_writev = mdwritev, + .smgr_writeback = mdwriteback, + .smgr_nblocks = mdnblocks, + .smgr_truncate = mdtruncate, + .smgr_immedsync = mdimmedsync, + .smgr_registersync = mdregistersync, + .smgr_fd = mdfd, + }; + + MdSMgrId = smgr_register(&md_smgr, sizeof(MdSMgrRelationData)); +} + /* local routines */ static void mdunlinkfork(RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo); -static MdfdVec *mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior); -static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, +static MdfdVec *mdopenfork(MdSMgrRelation reln, ForkNumber forknum, int behavior); +static void register_dirty_segment(MdSMgrRelation reln, ForkNumber forknum, MdfdVec *seg); static void register_unlink_segment(RelFileLocatorBackend rlocator, ForkNumber forknum, BlockNumber segno); static void register_forget_request(RelFileLocatorBackend rlocator, ForkNumber forknum, BlockNumber segno); -static void _fdvec_resize(SMgrRelation reln, +static void _fdvec_resize(MdSMgrRelation reln, ForkNumber forknum, int nseg); -static MdPathStr _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, +static MdPathStr _mdfd_segpath(MdSMgrRelation reln, ForkNumber forknum, BlockNumber segno); -static MdfdVec *_mdfd_openseg(SMgrRelation reln, ForkNumber forknum, +static MdfdVec *_mdfd_openseg(MdSMgrRelation reln, ForkNumber forknum, BlockNumber segno, int oflags); -static MdfdVec *_mdfd_getseg(SMgrRelation reln, ForkNumber forknum, +static MdfdVec *_mdfd_getseg(MdSMgrRelation reln, ForkNumber forknum, BlockNumber blkno, bool skipFsync, int behavior); -static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, +static BlockNumber _mdnblocks(MdSMgrRelation reln, ForkNumber forknum, MdfdVec *seg); -static PgAioResult md_readv_complete(PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data); static void md_readv_report(PgAioResult result, const PgAioTargetData *td, int elevel); -const PgAioHandleCallbacks aio_md_readv_cb = { +PgAioHandleCallbacks aio_md_readv_cb = { .complete_shared = md_readv_complete, .report = md_readv_report, }; @@ -192,6 +237,8 @@ mdinit(void) bool mdexists(SMgrRelation reln, ForkNumber forknum) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; + /* * Close it first, to ensure that we notice if the fork has been unlinked * since we opened it. As an optimization, we can skip that in recovery, @@ -200,7 +247,7 @@ mdexists(SMgrRelation reln, ForkNumber forknum) if (!InRecovery) mdclose(reln, forknum); - return (mdopenfork(reln, forknum, EXTENSION_RETURN_NULL) != NULL); + return (mdopenfork(mdreln, forknum, EXTENSION_RETURN_NULL) != NULL); } /* @@ -209,16 +256,17 @@ mdexists(SMgrRelation reln, ForkNumber forknum) * If isRedo is true, it's okay for the relation to exist already. */ void -mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) +mdcreate(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; MdfdVec *mdfd; RelPathStr path; File fd; - if (isRedo && reln->md_num_open_segs[forknum] > 0) + if (isRedo && mdreln->md_num_open_segs[forknum] > 0) return; /* created and opened already... */ - Assert(reln->md_num_open_segs[forknum] == 0); + Assert(mdreln->md_num_open_segs[forknum] == 0); /* * We may be using the target table space for the first time in this @@ -253,13 +301,13 @@ mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) } } - _fdvec_resize(reln, forknum, 1); - mdfd = &reln->md_seg_fds[forknum][0]; + _fdvec_resize(mdreln, forknum, 1); + mdfd = &mdreln->md_seg_fds[forknum][0]; mdfd->mdfd_vfd = fd; mdfd->mdfd_segno = 0; if (!SmgrIsTemp(reln)) - register_dirty_segment(reln, forknum, mdfd); + register_dirty_segment(mdreln, forknum, mdfd); } /* @@ -477,6 +525,7 @@ void mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; off_t seekpos; int nbytes; MdfdVec *v; @@ -503,7 +552,7 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, relpath(reln->smgr_rlocator, forknum).str, InvalidBlockNumber))); - v = _mdfd_getseg(reln, forknum, blocknum, skipFsync, EXTENSION_CREATE); + v = _mdfd_getseg(mdreln, forknum, blocknum, skipFsync, EXTENSION_CREATE); seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE)); @@ -527,9 +576,9 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, } if (!skipFsync && !SmgrIsTemp(reln)) - register_dirty_segment(reln, forknum, v); + register_dirty_segment(mdreln, forknum, v); - Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE)); + Assert(_mdnblocks(mdreln, forknum, v) <= ((BlockNumber) RELSEG_SIZE)); } /* @@ -542,6 +591,7 @@ void mdzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks, bool skipFsync) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; MdfdVec *v; BlockNumber curblocknum = blocknum; int remblocks = nblocks; @@ -576,7 +626,7 @@ mdzeroextend(SMgrRelation reln, ForkNumber forknum, else numblocks = remblocks; - v = _mdfd_getseg(reln, forknum, curblocknum, skipFsync, EXTENSION_CREATE); + v = _mdfd_getseg(mdreln, forknum, curblocknum, skipFsync, EXTENSION_CREATE); Assert(segstartblock < RELSEG_SIZE); Assert(segstartblock + numblocks <= RELSEG_SIZE); @@ -642,9 +692,9 @@ mdzeroextend(SMgrRelation reln, ForkNumber forknum, } if (!skipFsync && !SmgrIsTemp(reln)) - register_dirty_segment(reln, forknum, v); + register_dirty_segment(mdreln, forknum, v); - Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE)); + Assert(_mdnblocks(mdreln, forknum, v) <= ((BlockNumber) RELSEG_SIZE)); remblocks -= numblocks; curblocknum += numblocks; @@ -662,7 +712,7 @@ mdzeroextend(SMgrRelation reln, ForkNumber forknum, * invent one out of whole cloth. */ static MdfdVec * -mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior) +mdopenfork(MdSMgrRelation reln, ForkNumber forknum, int behavior) { MdfdVec *mdfd; RelPathStr path; @@ -672,7 +722,7 @@ mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior) if (reln->md_num_open_segs[forknum] > 0) return &reln->md_seg_fds[forknum][0]; - path = relpath(reln->smgr_rlocator, forknum); + path = relpath(reln->reln.smgr_rlocator, forknum); fd = PathNameOpenFile(path.str, _mdfd_open_flags()); @@ -702,9 +752,11 @@ mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior) void mdopen(SMgrRelation reln) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; + /* mark it not open */ for (int forknum = 0; forknum <= MAX_FORKNUM; forknum++) - reln->md_num_open_segs[forknum] = 0; + mdreln->md_num_open_segs[forknum] = 0; } /* @@ -713,7 +765,8 @@ mdopen(SMgrRelation reln) void mdclose(SMgrRelation reln, ForkNumber forknum) { - int nopensegs = reln->md_num_open_segs[forknum]; + MdSMgrRelation mdreln = (MdSMgrRelation) reln; + int nopensegs = mdreln->md_num_open_segs[forknum]; /* No work if already closed */ if (nopensegs == 0) @@ -722,10 +775,10 @@ mdclose(SMgrRelation reln, ForkNumber forknum) /* close segments starting from the end */ while (nopensegs > 0) { - MdfdVec *v = &reln->md_seg_fds[forknum][nopensegs - 1]; + MdfdVec *v = &mdreln->md_seg_fds[forknum][nopensegs - 1]; FileClose(v->mdfd_vfd); - _fdvec_resize(reln, forknum, nopensegs - 1); + _fdvec_resize(mdreln, forknum, nopensegs - 1); nopensegs--; } } @@ -738,6 +791,7 @@ mdprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks) { #ifdef USE_PREFETCH + MdSMgrRelation mdreln = (MdSMgrRelation) reln; Assert((io_direct_flags & IO_DIRECT_DATA) == 0); @@ -750,7 +804,7 @@ mdprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, MdfdVec *v; int nblocks_this_segment; - v = _mdfd_getseg(reln, forknum, blocknum, false, + v = _mdfd_getseg(mdreln, forknum, blocknum, false, InRecovery ? EXTENSION_RETURN_NULL : EXTENSION_FAIL); if (v == NULL) return false; @@ -848,6 +902,8 @@ void mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, void **buffers, BlockNumber nblocks) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; + while (nblocks > 0) { struct iovec iov[PG_IOV_MAX]; @@ -859,7 +915,7 @@ mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, size_t transferred_this_segment; size_t size_this_segment; - v = _mdfd_getseg(reln, forknum, blocknum, false, + v = _mdfd_getseg(mdreln, forknum, blocknum, false, EXTENSION_FAIL | EXTENSION_CREATE_RECOVERY); seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE)); @@ -987,6 +1043,7 @@ mdstartreadv(PgAioHandle *ioh, SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, void **buffers, BlockNumber nblocks) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; off_t seekpos; MdfdVec *v; BlockNumber nblocks_this_segment; @@ -994,7 +1051,7 @@ mdstartreadv(PgAioHandle *ioh, int iovcnt; int ret; - v = _mdfd_getseg(reln, forknum, blocknum, false, + v = _mdfd_getseg(mdreln, forknum, blocknum, false, EXTENSION_FAIL | EXTENSION_CREATE_RECOVERY); seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE)); @@ -1060,6 +1117,8 @@ void mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void **buffers, BlockNumber nblocks, bool skipFsync) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; + /* This assert is too expensive to have on normally ... */ #ifdef CHECK_WRITE_VS_EXTEND Assert((uint64) blocknum + (uint64) nblocks <= (uint64) mdnblocks(reln, forknum)); @@ -1076,7 +1135,7 @@ mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, size_t transferred_this_segment; size_t size_this_segment; - v = _mdfd_getseg(reln, forknum, blocknum, skipFsync, + v = _mdfd_getseg(mdreln, forknum, blocknum, skipFsync, EXTENSION_FAIL | EXTENSION_CREATE_RECOVERY); seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE)); @@ -1146,7 +1205,7 @@ mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, } if (!skipFsync && !SmgrIsTemp(reln)) - register_dirty_segment(reln, forknum, v); + register_dirty_segment(mdreln, forknum, v); nblocks -= nblocks_this_segment; buffers += nblocks_this_segment; @@ -1165,6 +1224,8 @@ void mdwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; + Assert((io_direct_flags & IO_DIRECT_DATA) == 0); /* @@ -1179,7 +1240,7 @@ mdwriteback(SMgrRelation reln, ForkNumber forknum, int segnum_start, segnum_end; - v = _mdfd_getseg(reln, forknum, blocknum, true /* not used */ , + v = _mdfd_getseg(mdreln, forknum, blocknum, true /* not used */ , EXTENSION_DONT_OPEN); /* @@ -1223,14 +1284,15 @@ mdwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; MdfdVec *v; BlockNumber nblocks; BlockNumber segno; - mdopenfork(reln, forknum, EXTENSION_FAIL); + mdopenfork(mdreln, forknum, EXTENSION_FAIL); /* mdopen has opened the first segment */ - Assert(reln->md_num_open_segs[forknum] > 0); + Assert(mdreln->md_num_open_segs[forknum] > 0); /* * Start from the last open segments, to avoid redundant seeks. We have @@ -1245,12 +1307,12 @@ mdnblocks(SMgrRelation reln, ForkNumber forknum) * that's OK because the checkpointer never needs to compute relation * size.) */ - segno = reln->md_num_open_segs[forknum] - 1; - v = &reln->md_seg_fds[forknum][segno]; + segno = mdreln->md_num_open_segs[forknum] - 1; + v = &mdreln->md_seg_fds[forknum][segno]; for (;;) { - nblocks = _mdnblocks(reln, forknum, v); + nblocks = _mdnblocks(mdreln, forknum, v); if (nblocks > ((BlockNumber) RELSEG_SIZE)) elog(FATAL, "segment too big"); if (nblocks < ((BlockNumber) RELSEG_SIZE)) @@ -1268,7 +1330,7 @@ mdnblocks(SMgrRelation reln, ForkNumber forknum) * undermines _mdfd_getseg's attempts to notice and report an error * upon access to a missing segment. */ - v = _mdfd_openseg(reln, forknum, segno, 0); + v = _mdfd_openseg(mdreln, forknum, segno, 0); if (v == NULL) return segno * ((BlockNumber) RELSEG_SIZE); } @@ -1291,6 +1353,7 @@ void mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber curnblk, BlockNumber nblocks) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; BlockNumber priorblocks; int curopensegs; @@ -1311,14 +1374,14 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, * Truncate segments, starting at the last one. Starting at the end makes * managing the memory for the fd array easier, should there be errors. */ - curopensegs = reln->md_num_open_segs[forknum]; + curopensegs = mdreln->md_num_open_segs[forknum]; while (curopensegs > 0) { MdfdVec *v; priorblocks = (curopensegs - 1) * RELSEG_SIZE; - v = &reln->md_seg_fds[forknum][curopensegs - 1]; + v = &mdreln->md_seg_fds[forknum][curopensegs - 1]; if (priorblocks > nblocks) { @@ -1333,13 +1396,13 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, FilePathName(v->mdfd_vfd)))); if (!SmgrIsTemp(reln)) - register_dirty_segment(reln, forknum, v); + register_dirty_segment(mdreln, forknum, v); /* we never drop the 1st segment */ - Assert(v != &reln->md_seg_fds[forknum][0]); + Assert(v != &mdreln->md_seg_fds[forknum][0]); FileClose(v->mdfd_vfd); - _fdvec_resize(reln, forknum, curopensegs - 1); + _fdvec_resize(mdreln, forknum, curopensegs - 1); } else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks) { @@ -1359,7 +1422,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, FilePathName(v->mdfd_vfd), nblocks))); if (!SmgrIsTemp(reln)) - register_dirty_segment(reln, forknum, v); + register_dirty_segment(mdreln, forknum, v); } else { @@ -1379,6 +1442,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, void mdregistersync(SMgrRelation reln, ForkNumber forknum) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; int segno; int min_inactive_seg; @@ -1388,7 +1452,7 @@ mdregistersync(SMgrRelation reln, ForkNumber forknum) */ mdnblocks(reln, forknum); - min_inactive_seg = segno = reln->md_num_open_segs[forknum]; + min_inactive_seg = segno = mdreln->md_num_open_segs[forknum]; /* * Temporarily open inactive segments, then close them after sync. There @@ -1396,20 +1460,20 @@ mdregistersync(SMgrRelation reln, ForkNumber forknum) * harmless. We don't bother to clean them up and take a risk of further * trouble. The next mdclose() will soon close them. */ - while (_mdfd_openseg(reln, forknum, segno, 0) != NULL) + while (_mdfd_openseg(mdreln, forknum, segno, 0) != NULL) segno++; while (segno > 0) { - MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1]; + MdfdVec *v = &mdreln->md_seg_fds[forknum][segno - 1]; - register_dirty_segment(reln, forknum, v); + register_dirty_segment(mdreln, forknum, v); /* Close inactive segments immediately */ if (segno > min_inactive_seg) { FileClose(v->mdfd_vfd); - _fdvec_resize(reln, forknum, segno - 1); + _fdvec_resize(mdreln, forknum, segno - 1); } segno--; @@ -1430,6 +1494,7 @@ mdregistersync(SMgrRelation reln, ForkNumber forknum) void mdimmedsync(SMgrRelation reln, ForkNumber forknum) { + MdSMgrRelation mdreln = (MdSMgrRelation) reln; int segno; int min_inactive_seg; @@ -1439,7 +1504,7 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum) */ mdnblocks(reln, forknum); - min_inactive_seg = segno = reln->md_num_open_segs[forknum]; + min_inactive_seg = segno = mdreln->md_num_open_segs[forknum]; /* * Temporarily open inactive segments, then close them after sync. There @@ -1447,12 +1512,12 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum) * is harmless. We don't bother to clean them up and take a risk of * further trouble. The next mdclose() will soon close them. */ - while (_mdfd_openseg(reln, forknum, segno, 0) != NULL) + while (_mdfd_openseg(mdreln, forknum, segno, 0) != NULL) segno++; while (segno > 0) { - MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1]; + MdfdVec *v = &mdreln->md_seg_fds[forknum][segno - 1]; /* * fsyncs done through mdimmedsync() should be tracked in a separate @@ -1473,7 +1538,7 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum) if (segno > min_inactive_seg) { FileClose(v->mdfd_vfd); - _fdvec_resize(reln, forknum, segno - 1); + _fdvec_resize(mdreln, forknum, segno - 1); } segno--; @@ -1483,9 +1548,10 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum) int mdfd(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, uint32 *off) { - MdfdVec *v = mdopenfork(reln, forknum, EXTENSION_FAIL); + MdSMgrRelation mdreln = (MdSMgrRelation) reln; + MdfdVec *v = mdopenfork(mdreln, forknum, EXTENSION_FAIL); - v = _mdfd_getseg(reln, forknum, blocknum, false, + v = _mdfd_getseg(mdreln, forknum, blocknum, false, EXTENSION_FAIL); *off = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE)); @@ -1505,14 +1571,14 @@ mdfd(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, uint32 *off) * enough to be a performance problem). */ static void -register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg) +register_dirty_segment(MdSMgrRelation reln, ForkNumber forknum, MdfdVec *seg) { FileTag tag; - INIT_MD_FILETAG(tag, reln->smgr_rlocator.locator, forknum, seg->mdfd_segno); + INIT_MD_FILETAG(tag, reln->reln.smgr_rlocator.locator, forknum, seg->mdfd_segno); /* Temp relations should never be fsync'd */ - Assert(!SmgrIsTemp(reln)); + Assert(!SmgrIsTemp(&reln->reln)); if (!RegisterSyncRequest(&tag, SYNC_REQUEST, false /* retryOnError */ )) { @@ -1630,7 +1696,7 @@ DropRelationFiles(RelFileLocator *delrels, int ndelrels, bool isRedo) * _fdvec_resize() -- Resize the fork's open segments array */ static void -_fdvec_resize(SMgrRelation reln, +_fdvec_resize(MdSMgrRelation reln, ForkNumber forknum, int nseg) { @@ -1678,12 +1744,12 @@ _fdvec_resize(SMgrRelation reln, * returned string is palloc'd. */ static MdPathStr -_mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno) +_mdfd_segpath(MdSMgrRelation reln, ForkNumber forknum, BlockNumber segno) { RelPathStr path; MdPathStr fullpath; - path = relpath(reln->smgr_rlocator, forknum); + path = relpath(reln->reln.smgr_rlocator, forknum); if (segno > 0) sprintf(fullpath.str, "%s.%u", path.str, segno); @@ -1698,7 +1764,7 @@ _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno) * and make a MdfdVec object for it. Returns NULL on failure. */ static MdfdVec * -_mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno, +_mdfd_openseg(MdSMgrRelation reln, ForkNumber forknum, BlockNumber segno, int oflags) { MdfdVec *v; @@ -1741,7 +1807,7 @@ _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno, * EXTENSION_CREATE case. */ static MdfdVec * -_mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno, +_mdfd_getseg(MdSMgrRelation reln, ForkNumber forknum, BlockNumber blkno, bool skipFsync, int behavior) { MdfdVec *v; @@ -1815,7 +1881,7 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno, char *zerobuf = palloc_aligned(BLCKSZ, PG_IO_ALIGN_SIZE, MCXT_ALLOC_ZERO); - mdextend(reln, forknum, + mdextend((SMgrRelation) reln, forknum, nextsegno * ((BlockNumber) RELSEG_SIZE) - 1, zerobuf, skipFsync); pfree(zerobuf); @@ -1870,7 +1936,7 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno, * Get number of blocks present in a single disk file */ static BlockNumber -_mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg) +_mdnblocks(MdSMgrRelation reln, ForkNumber forknum, MdfdVec *seg) { off_t len; @@ -1893,7 +1959,7 @@ _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg) int mdsyncfiletag(const FileTag *ftag, char *path) { - SMgrRelation reln = smgropen(ftag->rlocator, INVALID_PROC_NUMBER); + MdSMgrRelation reln = (MdSMgrRelation) smgropen(ftag->rlocator, INVALID_PROC_NUMBER); File file; instr_time io_start; bool need_to_close; @@ -1975,7 +2041,7 @@ mdfiletagmatches(const FileTag *ftag, const FileTag *candidate) /* * AIO completion callback for mdstartreadv(). */ -static PgAioResult +PgAioResult md_readv_complete(PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data) { PgAioTargetData *td = pgaio_io_get_target_data(ioh); diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 37b99fa319852..0f44ccd844aed 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -71,87 +71,20 @@ #include "storage/ipc.h" #include "storage/md.h" #include "storage/smgr.h" +#include "port/atomics.h" #include "utils/hsearch.h" #include "utils/inval.h" +#include "utils/memutils.h" +static f_smgr *smgrsw; -/* - * This struct of function pointers defines the API between smgr.c and - * any individual storage manager module. Note that smgr subfunctions are - * generally expected to report problems via elog(ERROR). An exception is - * that smgr_unlink should use elog(WARNING), rather than erroring out, - * because we normally unlink relations during post-commit/abort cleanup, - * and so it's too late to raise an error. Also, various conditions that - * would normally be errors should be allowed during bootstrap and/or WAL - * recovery --- see comments in md.c for details. - */ -typedef struct f_smgr -{ - void (*smgr_init) (void); /* may be NULL */ - void (*smgr_shutdown) (void); /* may be NULL */ - void (*smgr_open) (SMgrRelation reln); - void (*smgr_close) (SMgrRelation reln, ForkNumber forknum); - void (*smgr_create) (SMgrRelation reln, ForkNumber forknum, - bool isRedo); - bool (*smgr_exists) (SMgrRelation reln, ForkNumber forknum); - void (*smgr_unlink) (RelFileLocatorBackend rlocator, ForkNumber forknum, - bool isRedo); - void (*smgr_extend) (SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum, const void *buffer, bool skipFsync); - void (*smgr_zeroextend) (SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum, int nblocks, bool skipFsync); - bool (*smgr_prefetch) (SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum, int nblocks); - uint32 (*smgr_maxcombine) (SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum); - void (*smgr_readv) (SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum, - void **buffers, BlockNumber nblocks); - void (*smgr_startreadv) (PgAioHandle *ioh, - SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum, - void **buffers, BlockNumber nblocks); - void (*smgr_writev) (SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum, - const void **buffers, BlockNumber nblocks, - bool skipFsync); - void (*smgr_writeback) (SMgrRelation reln, ForkNumber forknum, - BlockNumber blocknum, BlockNumber nblocks); - BlockNumber (*smgr_nblocks) (SMgrRelation reln, ForkNumber forknum); - void (*smgr_truncate) (SMgrRelation reln, ForkNumber forknum, - BlockNumber old_blocks, BlockNumber nblocks); - void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum); - void (*smgr_registersync) (SMgrRelation reln, ForkNumber forknum); - int (*smgr_fd) (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, uint32 *off); -} f_smgr; - -static const f_smgr smgrsw[] = { - /* magnetic disk */ - { - .smgr_init = mdinit, - .smgr_shutdown = NULL, - .smgr_open = mdopen, - .smgr_close = mdclose, - .smgr_create = mdcreate, - .smgr_exists = mdexists, - .smgr_unlink = mdunlink, - .smgr_extend = mdextend, - .smgr_zeroextend = mdzeroextend, - .smgr_prefetch = mdprefetch, - .smgr_maxcombine = mdmaxcombine, - .smgr_readv = mdreadv, - .smgr_startreadv = mdstartreadv, - .smgr_writev = mdwritev, - .smgr_writeback = mdwriteback, - .smgr_nblocks = mdnblocks, - .smgr_truncate = mdtruncate, - .smgr_immedsync = mdimmedsync, - .smgr_registersync = mdregistersync, - .smgr_fd = mdfd, - } -}; +static int NSmgr = 0; + +static Size LargestSMgrRelationSize = 0; -static const int NSmgr = lengthof(smgrsw); +SMgrId storage_manager_id; + +bool allow_upstream_smgr_api = true; /* * Each backend has a hashtable that stores all extant SMgrRelation objects. @@ -175,6 +108,60 @@ const PgAioTargetInfo aio_smgr_target_info = { .describe_identity = smgr_aio_describe_identity, }; +#define MaxSMgrId UINT8_MAX + +SMgrId +smgr_register(const f_smgr *smgr, Size smgrrelation_size) +{ + SMgrId my_id; + MemoryContext old; + + if (process_shared_preload_libraries_done) + elog(FATAL, "SMgrs must be registered in the shared_preload_libraries phase"); + if (NSmgr == MaxSMgrId) + elog(FATAL, "Too many smgrs registered"); + if (smgr->name == NULL || *smgr->name == 0) + elog(FATAL, "smgr registered with invalid name"); + + Assert(smgr->smgr_open != NULL); + Assert(smgr->smgr_close != NULL); + Assert(smgr->smgr_create != NULL); + Assert(smgr->smgr_exists != NULL); + Assert(smgr->smgr_unlink != NULL); + Assert(smgr->smgr_extend != NULL); + Assert(smgr->smgr_zeroextend != NULL); + Assert(smgr->smgr_prefetch != NULL); + Assert(smgr->smgr_readv != NULL); + Assert(smgr->smgr_writev != NULL); + Assert(smgr->smgr_writeback != NULL); + Assert(smgr->smgr_nblocks != NULL); + Assert(smgr->smgr_truncate != NULL); + Assert(smgr->smgr_immedsync != NULL); + + old = MemoryContextSwitchTo(TopMemoryContext); + + my_id = NSmgr++; + if (my_id == 0) + smgrsw = palloc_array(f_smgr, 1); + else + smgrsw = repalloc_array(smgrsw, f_smgr, NSmgr); + + MemoryContextSwitchTo(old); + + pg_compiler_barrier(); + + if (!smgrsw) + { + NSmgr--; + elog(FATAL, "Failed to extend smgr array"); + } + + smgrsw[my_id] = *smgr; + + LargestSMgrRelationSize = Max(LargestSMgrRelationSize, smgrrelation_size); + + return my_id; +} /* * smgrinit(), smgrshutdown() -- Initialize or shut down storage @@ -252,8 +239,11 @@ smgropen(RelFileLocator rlocator, ProcNumber backend) /* First time through: initialize the hash table */ HASHCTL ctl; + LargestSMgrRelationSize = MAXALIGN(LargestSMgrRelationSize); + Assert(NSmgr > 0); + ctl.keysize = sizeof(RelFileLocatorBackend); - ctl.entrysize = sizeof(SMgrRelationData); + ctl.entrysize = LargestSMgrRelationSize; SMgrRelationHash = hash_create("smgr relation table", 400, &ctl, HASH_ELEM | HASH_BLOBS); dlist_init(&unpinned_relns); @@ -273,7 +263,8 @@ smgropen(RelFileLocator rlocator, ProcNumber backend) reln->smgr_targblock = InvalidBlockNumber; for (int i = 0; i <= MAX_FORKNUM; ++i) reln->smgr_cached_nblocks[i] = InvalidBlockNumber; - reln->smgr_which = 0; /* we only have md.c at present */ + + reln->smgr_which = storage_manager_id; /* it is not pinned yet */ reln->pincount = 0; @@ -470,6 +461,15 @@ smgrexists(SMgrRelation reln, ForkNumber forknum) return ret; } +void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) +{ + if(!allow_upstream_smgr_api) { + elog(FATAL, "An extension is trying to use the traditional smgrcreate method, while another loaded extension (pg_tde) requires the new API."); + } + + smgrcreate2(reln->smgr_rlocator.locator, reln, forknum, isRedo); +} + /* * smgrcreate() -- Create a new relation. * @@ -478,10 +478,10 @@ smgrexists(SMgrRelation reln, ForkNumber forknum) * to be created. */ void -smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) +smgrcreate2(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo) { HOLD_INTERRUPTS(); - smgrsw[reln->smgr_which].smgr_create(reln, forknum, isRedo); + smgrsw[reln->smgr_which].smgr_create(relold, reln, forknum, isRedo); RESUME_INTERRUPTS(); } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 559ba9cdb2cde..18cd9a93550d7 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -3880,7 +3880,7 @@ RelationSetNewRelfilenumber(Relation relation, char persistence) /* handle these directly, at least for now */ SMgrRelation srel; - srel = RelationCreateStorage(newrlocator, persistence, true); + srel = RelationCreateStorage2(relation->rd_locator, newrlocator, persistence, true); smgrclose(srel); } else diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index df182577a19e2..d0461c15331f3 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -43,6 +43,7 @@ #include "replication/slotsync.h" #include "storage/fd.h" #include "storage/ipc.h" +#include "storage/md.h" #include "storage/latch.h" #include "storage/pg_shmem.h" #include "storage/pmsignal.h" @@ -192,6 +193,9 @@ InitStandaloneProcess(const char *argv0) InitProcessLocalLatch(); InitializeLatchWaitSet(); + /* Initialize smgrs */ + register_builtin_dynamic_managers(); + /* * For consistency with InitPostmasterChild, initialize signal mask here. * But we don't unblock SIGQUIT or provide a default handler for it. @@ -1924,6 +1928,17 @@ process_session_preload_libraries(void) true); } +/* + * Register any internal managers. + */ +void +register_builtin_dynamic_managers(void) +{ + mdsmgr_register(); + + storage_manager_id = MdSMgrId; +} + /* * process any shared memory requests from preloaded libraries */ diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index b362ae437710d..17bf8c60beaaf 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -22,6 +22,7 @@ OBJS = \ guc_tables.o \ help_config.o \ injection_point.o \ + percona.o \ pg_config.o \ pg_controldata.o \ pg_rusage.o \ diff --git a/src/backend/utils/misc/meson.build b/src/backend/utils/misc/meson.build index 9e389a00d0576..584f8995e5467 100644 --- a/src/backend/utils/misc/meson.build +++ b/src/backend/utils/misc/meson.build @@ -7,6 +7,7 @@ backend_sources += files( 'guc_tables.c', 'help_config.c', 'injection_point.c', + 'percona.c', 'pg_config.c', 'pg_controldata.c', 'pg_rusage.c', diff --git a/src/backend/utils/misc/percona.c b/src/backend/utils/misc/percona.c new file mode 100644 index 0000000000000..7d65209bc609a --- /dev/null +++ b/src/backend/utils/misc/percona.c @@ -0,0 +1,15 @@ +/*------------------------------------------------------------------------- + * + * percona.c + * Percona specific functions + * + * IDENTIFICATION + * src/backend/utils/misc/percona.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "utils/percona.h" + +const int percona_api_version = PERCONA_API_VERSION; diff --git a/src/include/access/xlog_smgr.h b/src/include/access/xlog_smgr.h new file mode 100644 index 0000000000000..b1f7c4c425f48 --- /dev/null +++ b/src/include/access/xlog_smgr.h @@ -0,0 +1,41 @@ +#ifndef XLOG_SMGR_H +#define XLOG_SMGR_H + +#include "postgres.h" + +#include + +/* XLog storage manager interface */ +typedef struct XLogSmgr +{ + ssize_t (*seg_read) (int fd, void *buf, size_t count, off_t offset, + TimeLineID tli, XLogSegNo segno, int segSize); + + ssize_t (*seg_write) (int fd, const void *buf, size_t count, off_t offset, + TimeLineID tli, XLogSegNo segno, int segSize); +} XLogSmgr; + +static inline ssize_t +default_seg_write(int fd, const void *buf, size_t count, off_t offset, + TimeLineID tli, XLogSegNo segno, int segSize) +{ + return pg_pwrite(fd, buf, count, offset); +} + +static inline ssize_t +default_seg_read(int fd, void *buf, size_t count, off_t offset, + TimeLineID tli, XLogSegNo segno, int segSize) +{ + return pg_pread(fd, buf, count, offset); +} + +/* Default (standard) XLog storage manager */ +static const XLogSmgr xlog_smgr_standard = { + .seg_read = default_seg_read, + .seg_write = default_seg_write, +}; + +extern const XLogSmgr *xlog_smgr; +extern void SetXLogSmgr(const XLogSmgr *xlsmgr); + +#endif /* XLOG_SMGR_H */ diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 7f3a0ef5c6d35..63c59296a2298 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -17,6 +17,7 @@ #include "catalog/indexing.h" #include "catalog/objectaddress.h" #include "parser/parse_node.h" +#include "storage/relfilelocator.h" /* flag bits for CheckAttributeType/CheckAttributeNamesTypes */ @@ -62,7 +63,8 @@ extern Relation heap_create(const char *relname, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, - bool create_storage); + bool create_storage, + RelFileLocator *old_rlocator); extern Oid heap_create_with_catalog(const char *relname, Oid relnamespace, diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 4daa8bef5eeab..f0ca0b7c4a677 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -16,6 +16,7 @@ #include "catalog/objectaddress.h" #include "nodes/execnodes.h" +#include "storage/relfilelocator.h" #define DEFAULT_INDEX_TYPE "btree" @@ -88,6 +89,29 @@ extern Oid index_create(Relation heapRelation, bool is_internal, Oid *constraintId); +extern Oid index_create2(Relation heapRelation, + const char *indexRelationName, + Oid indexRelationId, + Oid parentIndexRelid, + Oid parentConstraintId, + RelFileNumber relFileNumber, + IndexInfo *indexInfo, + const List *indexColNames, + Oid accessMethodId, + Oid tableSpaceId, + const Oid *collationIds, + const Oid *opclassIds, + const Datum *opclassOptions, + const int16 *coloptions, + const NullableDatum *stattargets, + Datum reloptions, + bits16 flags, + bits16 constr_flags, + bool allow_system_table_mods, + bool is_internal, + Oid *constraintId, + RelFileLocator *old_rlocator); + #define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY (1 << 0) #define INDEX_CONSTR_CREATE_DEFERRABLE (1 << 1) #define INDEX_CONSTR_CREATE_INIT_DEFERRED (1 << 2) diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h index ba99225b0a37f..087cd35ec5a3c 100644 --- a/src/include/catalog/storage.h +++ b/src/include/catalog/storage.h @@ -25,6 +25,10 @@ extern PGDLLIMPORT int wal_skip_threshold; extern SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete); +extern SMgrRelation RelationCreateStorage2(RelFileLocator oldlocator, + RelFileLocator rlocator, + char relpersistence, + bool register_delete); extern void RelationDropStorage(Relation rel); extern void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit); extern void RelationPreTruncate(Relation rel); diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 9a7d733ddeffc..9784877617117 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -524,6 +524,7 @@ extern void TouchSocketLockFiles(void); extern void AddToDataDirLockFile(int target_line, const char *str); extern bool RecheckDataDirLockFile(void); extern void ValidatePgVersion(const char *path); +extern void register_builtin_dynamic_managers(void); extern void process_shared_preload_libraries(void); extern void process_session_preload_libraries(void); extern void process_shmem_requests(void); diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index c4dc5d72bdb78..4d77b0047f248 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -609,6 +609,9 @@ /* PostgreSQL minor version number */ #undef PG_MINORVERSION_NUM +/* PostgreSQL Percona version as a string */ +#undef PG_PERCONAVERSION + /* Define to best printf format archetype, usually gnu_printf if available. */ #undef PG_PRINTF_ATTRIBUTE @@ -684,6 +687,9 @@ /* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */ #undef USE_BSD_AUTH +/* Define to 1 to build with curl support. (--with-curl) */ +#undef USE_CURL + /* Define to build with ICU support. (--with-icu) */ #undef USE_ICU diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 125d3eb5fff5e..6eae34ab36258 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -361,3 +361,5 @@ * Enable tracing of syncscan operations (see also the trace_syncscan GUC var). */ /* #define TRACE_SYNCSCAN */ + +#define PERCONA_API_VERSION 2 diff --git a/src/include/storage/aio.h b/src/include/storage/aio.h index 2933eea064910..7a9c51212b963 100644 --- a/src/include/storage/aio.h +++ b/src/include/storage/aio.h @@ -200,7 +200,7 @@ typedef enum PgAioHandleCallbackID PGAIO_HCB_LOCAL_BUFFER_READV, } PgAioHandleCallbackID; -#define PGAIO_HCB_MAX PGAIO_HCB_LOCAL_BUFFER_READV +#define PGAIO_HCB_MAX 15 StaticAssertDecl(PGAIO_HCB_MAX < (1 << PGAIO_RESULT_ID_BITS), "PGAIO_HCB_MAX is too big for PGAIO_RESULT_ID_BITS"); @@ -308,6 +308,7 @@ extern PgAioTargetData *pgaio_io_get_target_data(PgAioHandle *ioh); extern char *pgaio_io_get_target_description(PgAioHandle *ioh); /* functions in aio_callback.c */ +extern PgAioHandleCallbackID pgaio_io_register_callback_entry(const PgAioHandleCallbacks *callback, const char *name); extern void pgaio_io_register_callbacks(PgAioHandle *ioh, PgAioHandleCallbackID cb_id, uint8 cb_data); extern void pgaio_io_set_handle_data_64(PgAioHandle *ioh, uint64 *data, uint8 len); diff --git a/src/include/storage/md.h b/src/include/storage/md.h index b563c27abf092..569a00336a6d2 100644 --- a/src/include/storage/md.h +++ b/src/include/storage/md.h @@ -20,13 +20,17 @@ #include "storage/smgr.h" #include "storage/sync.h" -extern PGDLLIMPORT const PgAioHandleCallbacks aio_md_readv_cb; +extern PGDLLIMPORT PgAioHandleCallbacks aio_md_readv_cb; + +/* registration function for md storage manager */ +extern void mdsmgr_register(void); +extern SMgrId MdSMgrId; /* md storage manager functionality */ extern void mdinit(void); extern void mdopen(SMgrRelation reln); extern void mdclose(SMgrRelation reln, ForkNumber forknum); -extern void mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo); +extern void mdcreate(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo); extern bool mdexists(SMgrRelation reln, ForkNumber forknum); extern void mdunlink(RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo); extern void mdextend(SMgrRelation reln, ForkNumber forknum, @@ -62,4 +66,7 @@ extern int mdsyncfiletag(const FileTag *ftag, char *path); extern int mdunlinkfiletag(const FileTag *ftag, char *path); extern bool mdfiletagmatches(const FileTag *ftag, const FileTag *candidate); +extern PgAioResult +md_readv_complete(PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data); + #endif /* MD_H */ diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index 3964d9334b3a7..e485944cb71c1 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -19,6 +19,11 @@ #include "storage/block.h" #include "storage/relfilelocator.h" +typedef uint8 SMgrId; + +extern PGDLLIMPORT SMgrId storage_manager_id; +extern bool allow_upstream_smgr_api; + /* * smgr.c maintains a table of SMgrRelation objects, which are essentially * cached file handles. An SMgrRelation is created (if not already present) @@ -52,14 +57,7 @@ typedef struct SMgrRelationData * Fields below here are intended to be private to smgr.c and its * submodules. Do not touch them from elsewhere. */ - int smgr_which; /* storage manager selector */ - - /* - * for md.c; per-fork arrays of the number of open segments - * (md_num_open_segs) and the segments themselves (md_seg_fds). - */ - int md_num_open_segs[MAX_FORKNUM + 1]; - struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1]; + SMgrId smgr_which; /* storage manager selector */ /* * Pinning support. If unpinned (ie. pincount == 0), 'node' is a list @@ -76,6 +74,59 @@ typedef SMgrRelationData *SMgrRelation; extern PGDLLIMPORT const PgAioTargetInfo aio_smgr_target_info; +/* + * This struct of function pointers defines the API between smgr.c and + * any individual storage manager module. Note that smgr subfunctions are + * generally expected to report problems via elog(ERROR). An exception is + * that smgr_unlink should use elog(WARNING), rather than erroring out, + * because we normally unlink relations during post-commit/abort cleanup, + * and so it's too late to raise an error. Also, various conditions that + * would normally be errors should be allowed during bootstrap and/or WAL + * recovery --- see comments in md.c for details. + */ +typedef struct f_smgr +{ + const char *name; + void (*smgr_init) (void); /* may be NULL */ + void (*smgr_shutdown) (void); /* may be NULL */ + void (*smgr_open) (SMgrRelation reln); + void (*smgr_close) (SMgrRelation reln, ForkNumber forknum); + void (*smgr_create) (RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, + bool isRedo); + bool (*smgr_exists) (SMgrRelation reln, ForkNumber forknum); + void (*smgr_unlink) (RelFileLocatorBackend rlocator, ForkNumber forknum, + bool isRedo); + void (*smgr_extend) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, const void *buffer, bool skipFsync); + void (*smgr_zeroextend) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, int nblocks, bool skipFsync); + bool (*smgr_prefetch) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, int nblocks); + uint32 (*smgr_maxcombine) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum); + void (*smgr_readv) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, + void **buffers, BlockNumber nblocks); + void (*smgr_startreadv) (PgAioHandle *ioh, + SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, + void **buffers, BlockNumber nblocks); + void (*smgr_writev) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, + const void **buffers, BlockNumber nblocks, + bool skipFsync); + void (*smgr_writeback) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, BlockNumber nblocks); + BlockNumber (*smgr_nblocks) (SMgrRelation reln, ForkNumber forknum); + void (*smgr_truncate) (SMgrRelation reln, ForkNumber forknum, + BlockNumber old_blocks, BlockNumber nblocks); + void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum); + void (*smgr_registersync) (SMgrRelation reln, ForkNumber forknum); + int (*smgr_fd) (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, uint32 *off); +} f_smgr; + +extern SMgrId smgr_register(const f_smgr *smgr, Size smgrrelation_size); + extern void smgrinit(void); extern SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend); extern bool smgrexists(SMgrRelation reln, ForkNumber forknum); @@ -87,6 +138,7 @@ extern void smgrrelease(SMgrRelation reln); extern void smgrreleaseall(void); extern void smgrreleaserellocator(RelFileLocatorBackend rlocator); extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo); +extern void smgrcreate2(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo); extern void smgrdosyncall(SMgrRelation *rels, int nrels); extern void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo); extern void smgrextend(SMgrRelation reln, ForkNumber forknum, diff --git a/src/include/utils/percona.h b/src/include/utils/percona.h new file mode 100644 index 0000000000000..e8de53618c551 --- /dev/null +++ b/src/include/utils/percona.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * percona.h + * Percona specific functions + * + * IDENTIFICATION + * src/include/utils/percona.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PERCONA__H__ +#define PERCONA__H__ + +extern const PGDLLIMPORT int percona_api_version; + +static inline void +check_percona_api_version(void) +{ + if (PERCONA_API_VERSION != percona_api_version) + { + elog(FATAL, "Percona API version mismatch, the extension was built against a different PostgreSQL version!"); + } +} + +#endif diff --git a/src/test/modules/test_misc/t/008_percona_server_version.pl b/src/test/modules/test_misc/t/008_percona_server_version.pl new file mode 100644 index 0000000000000..c6846048c5ee6 --- /dev/null +++ b/src/test/modules/test_misc/t/008_percona_server_version.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; +use lib 't'; +use Env; + +plan tests => 6; + +# Initialize a test cluster +my $node = PostgreSQL::Test::Cluster->new('pg_server'); +$node->init(); +my $pgdata = $node->data_dir; + +# To make this testcase work, PERCONA_SERVER_VERSION variable should be available in environment. +# If you are using ci_scripts it is already declated in ci_scripts/env.sh +# If you are using command line make for regression then export like: +# export PERCONA_SERVER_VERSION=17.6.1 + +if (!defined($ENV{PERCONA_SERVER_VERSION})) +{ + BAIL_OUT("PERCONA_SERVER_VERSION variable not present in the environment"); +} + +my $percona_expected_server_version = $ENV{PERCONA_SERVER_VERSION}; + +# Start server +my $rt_value = $node->start; +ok($rt_value == 1, "Start Server"); + +# Get PG Server version (e.g 17.4) from pg_config +my $pg_server_version = `pg_config --version | awk {'print \$2'}`; +$pg_server_version=~ s/^\s+|\s+$//g; + +# Check pg_config output. +my $pg_config_output = `pg_config --version`; +$pg_config_output=~ s/^\s+|\s+$//g; +cmp_ok($pg_config_output,'eq',"PostgreSQL $pg_server_version - Percona Server for PostgreSQL $percona_expected_server_version", "Test pg_config --version output"); + +# Check psql --version output. +my $psql_version_output = `psql --version`; +$psql_version_output=~ s/^\s+|\s+$//g; +cmp_ok($psql_version_output,'eq',"psql (PostgreSQL) $pg_server_version - Percona Server for PostgreSQL $percona_expected_server_version", "Test psql --version output"); + +# Check postgres --version output. +my $postgres_output = `postgres --version`; +$postgres_output=~ s/^\s+|\s+$//g; +cmp_ok($postgres_output,'eq',"postgres (PostgreSQL) $pg_server_version - Percona Server for PostgreSQL $percona_expected_server_version", "Test postgres --version output"); + +# Check select version() output. +my ($cmdret, $stdout, $stderr) = $node->psql('postgres', "select version();", extra_params => ['-a', '-Pformat=aligned','-Ptuples_only=on']); +ok($cmdret == 0, "# Get output of select version();"); +$stdout=~ s/^\s+|\s+$//g; +like($stdout, "/PostgreSQL $pg_server_version - Percona Server for PostgreSQL $percona_expected_server_version/", "Test select version() output"); + +# Stop the server +$node->stop; + +# Done testing for this testcase file. +done_testing(); diff --git a/src/test/regress/expected/create_am_1.out b/src/test/regress/expected/create_am_1.out new file mode 100644 index 0000000000000..822600ef23a59 --- /dev/null +++ b/src/test/regress/expected/create_am_1.out @@ -0,0 +1,577 @@ +-- +-- Create access method tests +-- +-- Make gist2 over gisthandler. In fact, it would be a synonym to gist. +CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler; +-- Verify return type checks for handlers +CREATE ACCESS METHOD bogus TYPE INDEX HANDLER int4in; +ERROR: function int4in(internal) does not exist +CREATE ACCESS METHOD bogus TYPE INDEX HANDLER heap_tableam_handler; +ERROR: function heap_tableam_handler must return type index_am_handler +-- Try to create gist2 index on fast_emp4000: fail because opclass doesn't exist +CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base); +ERROR: data type box has no default operator class for access method "gist2" +HINT: You must specify an operator class for the index or define a default operator class for the data type. +-- Make operator class for boxes using gist2 +CREATE OPERATOR CLASS box_ops DEFAULT + FOR TYPE box USING gist2 AS + OPERATOR 1 <<, + OPERATOR 2 &<, + OPERATOR 3 &&, + OPERATOR 4 &>, + OPERATOR 5 >>, + OPERATOR 6 ~=, + OPERATOR 7 @>, + OPERATOR 8 <@, + OPERATOR 9 &<|, + OPERATOR 10 <<|, + OPERATOR 11 |>>, + OPERATOR 12 |&>, + FUNCTION 1 gist_box_consistent(internal, box, smallint, oid, internal), + FUNCTION 2 gist_box_union(internal, internal), + -- don't need compress, decompress, or fetch functions + FUNCTION 5 gist_box_penalty(internal, internal, internal), + FUNCTION 6 gist_box_picksplit(internal, internal), + FUNCTION 7 gist_box_same(box, box, internal); +-- Create gist2 index on fast_emp4000 +CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base); +-- Now check the results from plain indexscan; temporarily drop existing +-- index grect2ind to ensure it doesn't capture the plan +BEGIN; +DROP INDEX grect2ind; +SET enable_seqscan = OFF; +SET enable_indexscan = ON; +SET enable_bitmapscan = OFF; +EXPLAIN (COSTS OFF) +SELECT * FROM fast_emp4000 + WHERE home_base <@ '(200,200),(2000,1000)'::box + ORDER BY (home_base[0])[0]; + QUERY PLAN +----------------------------------------------------------------- + Sort + Sort Key: ((home_base[0])[0]) + -> Index Only Scan using grect2ind2 on fast_emp4000 + Index Cond: (home_base <@ '(2000,1000),(200,200)'::box) +(4 rows) + +SELECT * FROM fast_emp4000 + WHERE home_base <@ '(200,200),(2000,1000)'::box + ORDER BY (home_base[0])[0]; + home_base +----------------------- + (337,455),(240,359) + (1444,403),(1346,344) +(2 rows) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; + QUERY PLAN +------------------------------------------------------------- + Aggregate + -> Index Only Scan using grect2ind2 on fast_emp4000 + Index Cond: (home_base && '(1000,1000),(0,0)'::box) +(3 rows) + +SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; + count +------- + 2 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Index Only Scan using grect2ind2 on fast_emp4000 + Index Cond: (home_base IS NULL) +(3 rows) + +SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; + count +------- + 278 +(1 row) + +ROLLBACK; +-- Try to drop access method: fail because of dependent objects +DROP ACCESS METHOD gist2; +ERROR: cannot drop access method gist2 because other objects depend on it +DETAIL: index grect2ind2 depends on operator class box_ops for access method gist2 +HINT: Use DROP ... CASCADE to drop the dependent objects too. +-- Drop access method cascade +-- To prevent a (rare) deadlock against autovacuum, +-- we must lock the table that owns the index that will be dropped +BEGIN; +LOCK TABLE fast_emp4000; +DROP ACCESS METHOD gist2 CASCADE; +NOTICE: drop cascades to index grect2ind2 +COMMIT; +-- +-- Test table access methods +-- +-- prevent empty values +SET default_table_access_method = ''; +ERROR: invalid value for parameter "default_table_access_method": "" +DETAIL: "default_table_access_method" cannot be empty. +-- prevent nonexistent values +SET default_table_access_method = 'I do not exist AM'; +ERROR: invalid value for parameter "default_table_access_method": "I do not exist AM" +DETAIL: Table access method "I do not exist AM" does not exist. +-- prevent setting it to an index AM +SET default_table_access_method = 'btree'; +ERROR: access method "btree" is not of type TABLE +-- Create a heap2 table am handler with heapam handler +CREATE ACCESS METHOD heap2 TYPE TABLE HANDLER heap_tableam_handler; +-- Verify return type checks for handlers +CREATE ACCESS METHOD bogus TYPE TABLE HANDLER int4in; +ERROR: function int4in(internal) does not exist +CREATE ACCESS METHOD bogus TYPE TABLE HANDLER bthandler; +ERROR: function bthandler must return type table_am_handler +SELECT amname, amhandler, amtype FROM pg_am where amtype = 't' ORDER BY 1, 2; + amname | amhandler | amtype +----------+--------------------------+-------- + heap | heap_tableam_handler | t + heap2 | heap_tableam_handler | t + tde_heap | _pg_tde.pg_tdeam_handler | t +(3 rows) + +-- First create tables employing the new AM using USING +-- plain CREATE TABLE +CREATE TABLE tableam_tbl_heap2(f1 int) USING heap2; +INSERT INTO tableam_tbl_heap2 VALUES(1); +SELECT f1 FROM tableam_tbl_heap2 ORDER BY f1; + f1 +---- + 1 +(1 row) + +-- CREATE TABLE AS +CREATE TABLE tableam_tblas_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2; +SELECT f1 FROM tableam_tbl_heap2 ORDER BY f1; + f1 +---- + 1 +(1 row) + +-- SELECT INTO doesn't support USING +SELECT INTO tableam_tblselectinto_heap2 USING heap2 FROM tableam_tbl_heap2; +ERROR: syntax error at or near "USING" +LINE 1: SELECT INTO tableam_tblselectinto_heap2 USING heap2 FROM tab... + ^ +-- CREATE VIEW doesn't support USING +CREATE VIEW tableam_view_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2; +ERROR: syntax error at or near "USING" +LINE 1: CREATE VIEW tableam_view_heap2 USING heap2 AS SELECT * FROM ... + ^ +-- CREATE SEQUENCE doesn't support USING +CREATE SEQUENCE tableam_seq_heap2 USING heap2; +ERROR: syntax error at or near "USING" +LINE 1: CREATE SEQUENCE tableam_seq_heap2 USING heap2; + ^ +-- CREATE MATERIALIZED VIEW does support USING +CREATE MATERIALIZED VIEW tableam_tblmv_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2; +SELECT f1 FROM tableam_tblmv_heap2 ORDER BY f1; + f1 +---- + 1 +(1 row) + +-- CREATE TABLE .. PARTITION BY supports USING. +CREATE TABLE tableam_parted_heap2 (a text, b int) PARTITION BY list (a) USING heap2; +SELECT a.amname FROM pg_class c, pg_am a + WHERE c.relname = 'tableam_parted_heap2' AND a.oid = c.relam; + amname +-------- + heap2 +(1 row) + +DROP TABLE tableam_parted_heap2; +CREATE TABLE tableam_parted_heap2 (a text, b int) PARTITION BY list (a); +-- new partitions will inherit from the current default, rather the partition root +SET default_table_access_method = 'heap'; +CREATE TABLE tableam_parted_a_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('a'); +SET default_table_access_method = 'heap2'; +CREATE TABLE tableam_parted_b_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('b'); +RESET default_table_access_method; +-- but the method can be explicitly specified +CREATE TABLE tableam_parted_c_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('c') USING heap; +CREATE TABLE tableam_parted_d_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('d') USING heap2; +-- List all objects in AM +SELECT + pc.relkind, + pa.amname, + CASE WHEN relkind = 't' THEN + (SELECT 'toast for ' || relname::regclass FROM pg_class pcm WHERE pcm.reltoastrelid = pc.oid) + ELSE + relname::regclass::text + END COLLATE "C" AS relname +FROM pg_class AS pc, + pg_am AS pa +WHERE pa.oid = pc.relam + AND pa.amname = 'heap2' +ORDER BY 3, 1, 2; + relkind | amname | relname +---------+--------+---------------------------------- + r | heap2 | tableam_parted_b_heap2 + r | heap2 | tableam_parted_d_heap2 + r | heap2 | tableam_tbl_heap2 + r | heap2 | tableam_tblas_heap2 + m | heap2 | tableam_tblmv_heap2 + t | heap2 | toast for tableam_parted_b_heap2 + t | heap2 | toast for tableam_parted_d_heap2 +(7 rows) + +-- Show dependencies onto AM - there shouldn't be any for toast +SELECT pg_describe_object(classid,objid,objsubid) AS obj +FROM pg_depend, pg_am +WHERE pg_depend.refclassid = 'pg_am'::regclass + AND pg_am.oid = pg_depend.refobjid + AND pg_am.amname = 'heap2' +ORDER BY classid, objid, objsubid; + obj +--------------------------------------- + table tableam_tbl_heap2 + table tableam_tblas_heap2 + materialized view tableam_tblmv_heap2 + table tableam_parted_b_heap2 + table tableam_parted_d_heap2 +(5 rows) + +-- ALTER TABLE SET ACCESS METHOD +CREATE TABLE heaptable USING heap AS + SELECT a, repeat(a::text, 100) FROM generate_series(1,9) AS a; +SELECT amname FROM pg_class c, pg_am am + WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; + amname +-------- + heap +(1 row) + +-- Switching to heap2 adds new dependency entry to the AM. +ALTER TABLE heaptable SET ACCESS METHOD heap2; +SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_describe_object(refclassid, refobjid, refobjsubid) as objref, + deptype + FROM pg_depend + WHERE classid = 'pg_class'::regclass AND + objid = 'heaptable'::regclass + ORDER BY 1, 2; + obj | objref | deptype +-----------------+---------------------+--------- + table heaptable | access method heap2 | n + table heaptable | schema public | n +(2 rows) + +-- Switching to heap should not have a dependency entry to the AM. +ALTER TABLE heaptable SET ACCESS METHOD heap; +SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_describe_object(refclassid, refobjid, refobjsubid) as objref, + deptype + FROM pg_depend + WHERE classid = 'pg_class'::regclass AND + objid = 'heaptable'::regclass + ORDER BY 1, 2; + obj | objref | deptype +-----------------+---------------+--------- + table heaptable | schema public | n +(1 row) + +ALTER TABLE heaptable SET ACCESS METHOD heap2; +SELECT amname FROM pg_class c, pg_am am + WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; + amname +-------- + heap2 +(1 row) + +SELECT COUNT(a), COUNT(1) FILTER(WHERE a=1) FROM heaptable; + count | count +-------+------- + 9 | 1 +(1 row) + +-- DEFAULT access method +BEGIN; +SET LOCAL default_table_access_method TO heap2; +ALTER TABLE heaptable SET ACCESS METHOD DEFAULT; +SELECT amname FROM pg_class c, pg_am am + WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; + amname +-------- + heap2 +(1 row) + +SET LOCAL default_table_access_method TO heap; +ALTER TABLE heaptable SET ACCESS METHOD DEFAULT; +SELECT amname FROM pg_class c, pg_am am + WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; + amname +-------- + heap +(1 row) + +ROLLBACK; +-- ALTER MATERIALIZED VIEW SET ACCESS METHOD +CREATE MATERIALIZED VIEW heapmv USING heap AS SELECT * FROM heaptable; +SELECT amname FROM pg_class c, pg_am am + WHERE c.relam = am.oid AND c.oid = 'heapmv'::regclass; + amname +-------- + heap +(1 row) + +ALTER MATERIALIZED VIEW heapmv SET ACCESS METHOD heap2; +SELECT amname FROM pg_class c, pg_am am + WHERE c.relam = am.oid AND c.oid = 'heapmv'::regclass; + amname +-------- + heap2 +(1 row) + +SELECT COUNT(a), COUNT(1) FILTER(WHERE a=1) FROM heapmv; + count | count +-------+------- + 9 | 1 +(1 row) + +-- No support for multiple subcommands +ALTER TABLE heaptable SET ACCESS METHOD heap, SET ACCESS METHOD heap2; +ERROR: cannot have multiple SET ACCESS METHOD subcommands +ALTER TABLE heaptable SET ACCESS METHOD DEFAULT, SET ACCESS METHOD heap2; +ERROR: cannot have multiple SET ACCESS METHOD subcommands +ALTER MATERIALIZED VIEW heapmv SET ACCESS METHOD heap, SET ACCESS METHOD heap2; +ERROR: cannot have multiple SET ACCESS METHOD subcommands +DROP MATERIALIZED VIEW heapmv; +DROP TABLE heaptable; +-- Partitioned table with USING +CREATE TABLE am_partitioned(x INT, y INT) PARTITION BY hash (x) USING heap2; +SELECT pg_describe_object(classid, objid, objsubid) AS obj, + pg_describe_object(refclassid, refobjid, refobjsubid) as refobj + FROM pg_depend, pg_am + WHERE pg_depend.refclassid = 'pg_am'::regclass + AND pg_am.oid = pg_depend.refobjid + AND pg_depend.objid = 'am_partitioned'::regclass; + obj | refobj +----------------------+--------------------- + table am_partitioned | access method heap2 +(1 row) + +DROP TABLE am_partitioned; +-- Partition hierarchies with access methods +BEGIN; +SET LOCAL default_table_access_method = 'heap'; +CREATE TABLE am_partitioned(x INT, y INT) PARTITION BY hash (x); +-- pg_class.relam is 0, no dependency recorded between the AM and the +-- partitioned table. +SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; + relam +------- + 0 +(1 row) + +SELECT pg_describe_object(classid, objid, objsubid) AS obj, + pg_describe_object(refclassid, refobjid, refobjsubid) as refobj + FROM pg_depend, pg_am + WHERE pg_depend.refclassid = 'pg_am'::regclass + AND pg_am.oid = pg_depend.refobjid + AND pg_depend.objid = 'am_partitioned'::regclass; + obj | refobj +-----+-------- +(0 rows) + +-- New default is set, with dependency added. +ALTER TABLE am_partitioned SET ACCESS METHOD heap2; +SELECT a.amname FROM pg_class c, pg_am a + WHERE c.relname = 'am_partitioned' AND a.oid = c.relam; + amname +-------- + heap2 +(1 row) + +SELECT pg_describe_object(classid, objid, objsubid) AS obj, + pg_describe_object(refclassid, refobjid, refobjsubid) as refobj + FROM pg_depend, pg_am + WHERE pg_depend.refclassid = 'pg_am'::regclass + AND pg_am.oid = pg_depend.refobjid + AND pg_depend.objid = 'am_partitioned'::regclass; + obj | refobj +----------------------+--------------------- + table am_partitioned | access method heap2 +(1 row) + +-- Default is set, with dependency updated. +SET LOCAL default_table_access_method = 'heap2'; +ALTER TABLE am_partitioned SET ACCESS METHOD heap; +SELECT a.amname FROM pg_class c, pg_am a + WHERE c.relname = 'am_partitioned' AND a.oid = c.relam; + amname +-------- + heap +(1 row) + +-- Dependency pinned, hence removed. +SELECT pg_describe_object(classid, objid, objsubid) AS obj, + pg_describe_object(refclassid, refobjid, refobjsubid) as refobj + FROM pg_depend, pg_am + WHERE pg_depend.refclassid = 'pg_am'::regclass + AND pg_am.oid = pg_depend.refobjid + AND pg_depend.objid = 'am_partitioned'::regclass; + obj | refobj +-----+-------- +(0 rows) + +-- Default and AM set in the clause are the same, relam should be set. +SET LOCAL default_table_access_method = 'heap2'; +ALTER TABLE am_partitioned SET ACCESS METHOD heap2; +SELECT a.amname FROM pg_class c, pg_am a + WHERE c.relname = 'am_partitioned' AND a.oid = c.relam; + amname +-------- + heap2 +(1 row) + +-- Reset to default +ALTER TABLE am_partitioned SET ACCESS METHOD DEFAULT; +SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; + relam +------- + 0 +(1 row) + +-- Upon ALTER TABLE SET ACCESS METHOD on a partitioned table, new partitions +-- will inherit the AM set. Existing partitioned are unchanged. +SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; + relam +------- + 0 +(1 row) + +SET LOCAL default_table_access_method = 'heap'; +CREATE TABLE am_partitioned_0 PARTITION OF am_partitioned + FOR VALUES WITH (MODULUS 10, REMAINDER 0); +SET LOCAL default_table_access_method = 'heap2'; +CREATE TABLE am_partitioned_1 PARTITION OF am_partitioned + FOR VALUES WITH (MODULUS 10, REMAINDER 1); +SET LOCAL default_table_access_method = 'heap'; +ALTER TABLE am_partitioned SET ACCESS METHOD heap2; +CREATE TABLE am_partitioned_2 PARTITION OF am_partitioned + FOR VALUES WITH (MODULUS 10, REMAINDER 2); +ALTER TABLE am_partitioned SET ACCESS METHOD DEFAULT; +SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; + relam +------- + 0 +(1 row) + +CREATE TABLE am_partitioned_3 PARTITION OF am_partitioned + FOR VALUES WITH (MODULUS 10, REMAINDER 3); +-- Partitioned table with relam at 0 +ALTER TABLE am_partitioned SET ACCESS METHOD DEFAULT; +CREATE TABLE am_partitioned_5p PARTITION OF am_partitioned + FOR VALUES WITH (MODULUS 10, REMAINDER 5) PARTITION BY hash(y); +-- Partitions of this partitioned table inherit default AM at creation +-- time. +CREATE TABLE am_partitioned_5p1 PARTITION OF am_partitioned_5p + FOR VALUES WITH (MODULUS 10, REMAINDER 1); +-- Partitioned table with relam set. +ALTER TABLE am_partitioned SET ACCESS METHOD heap2; +CREATE TABLE am_partitioned_6p PARTITION OF am_partitioned + FOR VALUES WITH (MODULUS 10, REMAINDER 6) PARTITION BY hash(y); +-- Partitions of this partitioned table inherit its AM. +CREATE TABLE am_partitioned_6p1 PARTITION OF am_partitioned_6p + FOR VALUES WITH (MODULUS 10, REMAINDER 1); +SELECT c.relname, a.amname FROM pg_class c, pg_am a + WHERE c.relam = a.oid AND + c.relname LIKE 'am_partitioned%' +UNION ALL +SELECT c.relname, 'default' FROM pg_class c + WHERE c.relam = 0 + AND c.relname LIKE 'am_partitioned%' ORDER BY 1; + relname | amname +--------------------+--------- + am_partitioned | heap2 + am_partitioned_0 | heap + am_partitioned_1 | heap2 + am_partitioned_2 | heap2 + am_partitioned_3 | heap + am_partitioned_5p | default + am_partitioned_5p1 | heap + am_partitioned_6p | heap2 + am_partitioned_6p1 | heap2 +(9 rows) + +DROP TABLE am_partitioned; +COMMIT; +-- Second, create objects in the new AM by changing the default AM +BEGIN; +SET LOCAL default_table_access_method = 'heap2'; +-- following tests should all respect the default AM +CREATE TABLE tableam_tbl_heapx(f1 int); +CREATE TABLE tableam_tblas_heapx AS SELECT * FROM tableam_tbl_heapx; +SELECT INTO tableam_tblselectinto_heapx FROM tableam_tbl_heapx; +CREATE MATERIALIZED VIEW tableam_tblmv_heapx USING heap2 AS SELECT * FROM tableam_tbl_heapx; +CREATE TABLE tableam_parted_heapx (a text, b int) PARTITION BY list (a); +CREATE TABLE tableam_parted_1_heapx PARTITION OF tableam_parted_heapx FOR VALUES IN ('a', 'b'); +-- but an explicitly set AM overrides it +CREATE TABLE tableam_parted_2_heapx PARTITION OF tableam_parted_heapx FOR VALUES IN ('c', 'd') USING heap; +-- sequences, views and foreign servers shouldn't have an AM +CREATE VIEW tableam_view_heapx AS SELECT * FROM tableam_tbl_heapx; +CREATE SEQUENCE tableam_seq_heapx; +CREATE FOREIGN DATA WRAPPER fdw_heap2 VALIDATOR postgresql_fdw_validator; +CREATE SERVER fs_heap2 FOREIGN DATA WRAPPER fdw_heap2 ; +CREATE FOREIGN table tableam_fdw_heapx () SERVER fs_heap2; +-- Verify that new AM was used for tables, matviews, but not for sequences, views and fdws +SELECT + pc.relkind, + pa.amname, + CASE WHEN relkind = 't' THEN + (SELECT 'toast for ' || relname::regclass FROM pg_class pcm WHERE pcm.reltoastrelid = pc.oid) + ELSE + relname::regclass::text + END COLLATE "C" AS relname +FROM pg_class AS pc + LEFT JOIN pg_am AS pa ON (pa.oid = pc.relam) +WHERE pc.relname LIKE 'tableam_%_heapx' +ORDER BY 3, 1, 2; + relkind | amname | relname +---------+--------+----------------------------- + f | | tableam_fdw_heapx + r | heap2 | tableam_parted_1_heapx + r | heap | tableam_parted_2_heapx + p | | tableam_parted_heapx + S | | tableam_seq_heapx + r | heap2 | tableam_tbl_heapx + r | heap2 | tableam_tblas_heapx + m | heap2 | tableam_tblmv_heapx + r | heap2 | tableam_tblselectinto_heapx + v | | tableam_view_heapx +(10 rows) + +-- don't want to keep those tables, nor the default +ROLLBACK; +-- Third, check that we can neither create a table using a nonexistent +-- AM, nor using an index AM +CREATE TABLE i_am_a_failure() USING ""; +ERROR: zero-length delimited identifier at or near """" +LINE 1: CREATE TABLE i_am_a_failure() USING ""; + ^ +CREATE TABLE i_am_a_failure() USING i_do_not_exist_am; +ERROR: access method "i_do_not_exist_am" does not exist +CREATE TABLE i_am_a_failure() USING "I do not exist AM"; +ERROR: access method "I do not exist AM" does not exist +CREATE TABLE i_am_a_failure() USING "btree"; +ERROR: access method "btree" is not of type TABLE +-- Other weird invalid cases that cause problems +CREATE FOREIGN TABLE fp PARTITION OF tableam_parted_a_heap2 DEFAULT SERVER x; +ERROR: "tableam_parted_a_heap2" is not partitioned +-- Drop table access method, which fails as objects depends on it +DROP ACCESS METHOD heap2; +ERROR: cannot drop access method heap2 because other objects depend on it +DETAIL: table tableam_tbl_heap2 depends on access method heap2 +table tableam_tblas_heap2 depends on access method heap2 +materialized view tableam_tblmv_heap2 depends on access method heap2 +table tableam_parted_b_heap2 depends on access method heap2 +table tableam_parted_d_heap2 depends on access method heap2 +HINT: Use DROP ... CASCADE to drop the dependent objects too. +-- we intentionally leave the objects created above alive, to verify pg_dump support diff --git a/src/test/regress/expected/create_index_1.out b/src/test/regress/expected/create_index_1.out new file mode 100644 index 0000000000000..248e4e554032f --- /dev/null +++ b/src/test/regress/expected/create_index_1.out @@ -0,0 +1,3577 @@ +-- +-- CREATE_INDEX +-- Create ancillary data structures (i.e. indices) +-- +-- directory paths are passed to us in environment variables +\getenv abs_srcdir PG_ABS_SRCDIR +-- +-- BTREE +-- +CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); +CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops); +NOTICE: relation "onek_unique1" already exists, skipping +CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops); +ERROR: syntax error at or near "ON" +LINE 1: CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_... + ^ +CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops); +CREATE INDEX onek_hundred ON onek USING btree(hundred int4_ops); +CREATE INDEX onek_stringu1 ON onek USING btree(stringu1 name_ops); +CREATE INDEX tenk1_unique1 ON tenk1 USING btree(unique1 int4_ops); +CREATE INDEX tenk1_unique2 ON tenk1 USING btree(unique2 int4_ops); +CREATE INDEX tenk1_hundred ON tenk1 USING btree(hundred int4_ops); +CREATE INDEX tenk1_thous_tenthous ON tenk1 (thousand, tenthous); +CREATE INDEX tenk2_unique1 ON tenk2 USING btree(unique1 int4_ops); +CREATE INDEX tenk2_unique2 ON tenk2 USING btree(unique2 int4_ops); +CREATE INDEX tenk2_hundred ON tenk2 USING btree(hundred int4_ops); +CREATE INDEX rix ON road USING btree (name text_ops); +CREATE INDEX iix ON ihighway USING btree (name text_ops); +CREATE INDEX six ON shighway USING btree (name text_ops); +-- test comments +COMMENT ON INDEX six_wrong IS 'bad index'; +ERROR: relation "six_wrong" does not exist +COMMENT ON INDEX six IS 'good index'; +COMMENT ON INDEX six IS NULL; +-- +-- BTREE partial indices +-- +CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) + where unique1 < 20 or unique1 > 980; +CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) + where stringu1 < 'B'; +CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops) + where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K'; +-- +-- GiST (rtree-equivalent opclasses only) +-- +CREATE TABLE slow_emp4000 ( + home_base box +); +CREATE TABLE fast_emp4000 ( + home_base box +); +\set filename :abs_srcdir '/data/rect.data' +COPY slow_emp4000 FROM :'filename'; +INSERT INTO fast_emp4000 SELECT * FROM slow_emp4000; +ANALYZE slow_emp4000; +ANALYZE fast_emp4000; +CREATE INDEX grect2ind ON fast_emp4000 USING gist (home_base); +-- we want to work with a point_tbl that includes a null +CREATE TEMP TABLE point_tbl AS SELECT * FROM public.point_tbl; +INSERT INTO POINT_TBL(f1) VALUES (NULL); +CREATE INDEX gpointind ON point_tbl USING gist (f1); +CREATE TEMP TABLE gpolygon_tbl AS + SELECT polygon(home_base) AS f1 FROM slow_emp4000; +INSERT INTO gpolygon_tbl VALUES ( '(1000,0,0,1000)' ); +INSERT INTO gpolygon_tbl VALUES ( '(0,1000,1000,1000)' ); +CREATE TEMP TABLE gcircle_tbl AS + SELECT circle(home_base) AS f1 FROM slow_emp4000; +CREATE INDEX ggpolygonind ON gpolygon_tbl USING gist (f1); +CREATE INDEX ggcircleind ON gcircle_tbl USING gist (f1); +-- +-- Test GiST indexes +-- +-- get non-indexed results for comparison purposes +SET enable_seqscan = ON; +SET enable_indexscan = OFF; +SET enable_bitmapscan = OFF; +SELECT * FROM fast_emp4000 + WHERE home_base <@ '(200,200),(2000,1000)'::box + ORDER BY (home_base[0])[0]; + home_base +----------------------- + (337,455),(240,359) + (1444,403),(1346,344) +(2 rows) + +SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; + count +------- + 2 +(1 row) + +SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; + count +------- + 278 +(1 row) + +SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon; + count +------- + 2 +(1 row) + +SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle; + count +------- + 2 +(1 row) + +SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)'; + count +------- + 3 +(1 row) + +SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1; + count +------- + 3 +(1 row) + +SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)'; + count +------- + 5 +(1 row) + +SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; + count +------- + 1 +(1 row) + +SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)'; + count +------- + 3 +(1 row) + +SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)'; + count +------- + 4 +(1 row) + +SELECT count(*) FROM point_tbl p WHERE p.f1 <<| '(0.0, 0.0)'; + count +------- + 1 +(1 row) + +SELECT count(*) FROM point_tbl p WHERE p.f1 |>> '(0.0, 0.0)'; + count +------- + 5 +(1 row) + +SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)'; + count +------- + 1 +(1 row) + +SELECT * FROM point_tbl ORDER BY f1 <-> '0,1'; + f1 +------------------- + (0,0) + (1e-300,-1e-300) + (-3,4) + (-10,0) + (10,10) + (-5,-12) + (5.1,34.5) + (Infinity,1e+300) + (1e+300,Infinity) + (NaN,NaN) + +(11 rows) + +SELECT * FROM point_tbl WHERE f1 IS NULL; + f1 +---- + +(1 row) + +SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1'; + f1 +------------------- + (0,0) + (1e-300,-1e-300) + (-3,4) + (-10,0) + (10,10) + (-5,-12) + (5.1,34.5) + (1e+300,Infinity) + (Infinity,1e+300) + (NaN,NaN) +(10 rows) + +SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; + f1 +------------------ + (0,0) + (1e-300,-1e-300) + (-3,4) + (-10,0) + (10,10) +(5 rows) + +SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10; + f1 +------------------------------------------------- + ((240,359),(240,455),(337,455),(337,359)) + ((662,163),(662,187),(759,187),(759,163)) + ((1000,0),(0,1000)) + ((0,1000),(1000,1000)) + ((1346,344),(1346,403),(1444,403),(1444,344)) + ((278,1409),(278,1457),(369,1457),(369,1409)) + ((907,1156),(907,1201),(948,1201),(948,1156)) + ((1517,971),(1517,1043),(1594,1043),(1594,971)) + ((175,1820),(175,1850),(259,1850),(259,1820)) + ((2424,81),(2424,160),(2424,160),(2424,81)) +(10 rows) + +SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10; + circle_center | radius +----------------+-------- + (288.5,407) | 68 + (710.5,175) | 50 + (323.5,1433) | 51 + (927.5,1178.5) | 30 + (1395,373.5) | 57 + (1555.5,1007) | 53 + (217,1835) | 45 + (489,2421.5) | 22 + (2424,120.5) | 40 + (751.5,2655) | 20 +(10 rows) + +-- Now check the results from plain indexscan +SET enable_seqscan = OFF; +SET enable_indexscan = ON; +SET enable_bitmapscan = OFF; +EXPLAIN (COSTS OFF) +SELECT * FROM fast_emp4000 + WHERE home_base <@ '(200,200),(2000,1000)'::box + ORDER BY (home_base[0])[0]; + QUERY PLAN +----------------------------------------------------------------- + Sort + Sort Key: ((home_base[0])[0]) + -> Index Only Scan using grect2ind on fast_emp4000 + Index Cond: (home_base <@ '(2000,1000),(200,200)'::box) +(4 rows) + +SELECT * FROM fast_emp4000 + WHERE home_base <@ '(200,200),(2000,1000)'::box + ORDER BY (home_base[0])[0]; + home_base +----------------------- + (337,455),(240,359) + (1444,403),(1346,344) +(2 rows) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; + QUERY PLAN +------------------------------------------------------------- + Aggregate + -> Index Only Scan using grect2ind on fast_emp4000 + Index Cond: (home_base && '(1000,1000),(0,0)'::box) +(3 rows) + +SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; + count +------- + 2 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; + QUERY PLAN +------------------------------------------------------- + Aggregate + -> Index Only Scan using grect2ind on fast_emp4000 + Index Cond: (home_base IS NULL) +(3 rows) + +SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; + count +------- + 278 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon; + QUERY PLAN +------------------------------------------------------------ + Aggregate + -> Index Scan using ggpolygonind on gpolygon_tbl + Index Cond: (f1 && '((1000,1000),(0,0))'::polygon) +(3 rows) + +SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon; + count +------- + 2 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle; + QUERY PLAN +------------------------------------------------------- + Aggregate + -> Index Scan using ggcircleind on gcircle_tbl + Index Cond: (f1 && '<(500,500),500>'::circle) +(3 rows) + +SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle; + count +------- + 2 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)'; + QUERY PLAN +---------------------------------------------------- + Aggregate + -> Index Only Scan using gpointind on point_tbl + Index Cond: (f1 <@ '(100,100),(0,0)'::box) +(3 rows) + +SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)'; + count +------- + 3 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1; + QUERY PLAN +---------------------------------------------------- + Aggregate + -> Index Only Scan using gpointind on point_tbl + Index Cond: (f1 <@ '(100,100),(0,0)'::box) +(3 rows) + +SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1; + count +------- + 3 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)'; + QUERY PLAN +---------------------------------------------------------------------------------------- + Aggregate + -> Index Only Scan using gpointind on point_tbl + Index Cond: (f1 <@ '((0,0),(0,100),(100,100),(50,50),(100,0),(0,0))'::polygon) +(3 rows) + +SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)'; + count +------- + 4 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; + QUERY PLAN +---------------------------------------------------- + Aggregate + -> Index Only Scan using gpointind on point_tbl + Index Cond: (f1 <@ '<(50,50),50>'::circle) +(3 rows) + +SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)'; + QUERY PLAN +------------------------------------------------------ + Aggregate + -> Index Only Scan using gpointind on point_tbl p + Index Cond: (f1 << '(0,0)'::point) +(3 rows) + +SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)'; + count +------- + 3 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)'; + QUERY PLAN +------------------------------------------------------ + Aggregate + -> Index Only Scan using gpointind on point_tbl p + Index Cond: (f1 >> '(0,0)'::point) +(3 rows) + +SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)'; + count +------- + 4 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl p WHERE p.f1 <<| '(0.0, 0.0)'; + QUERY PLAN +------------------------------------------------------ + Aggregate + -> Index Only Scan using gpointind on point_tbl p + Index Cond: (f1 <<| '(0,0)'::point) +(3 rows) + +SELECT count(*) FROM point_tbl p WHERE p.f1 <<| '(0.0, 0.0)'; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl p WHERE p.f1 |>> '(0.0, 0.0)'; + QUERY PLAN +------------------------------------------------------ + Aggregate + -> Index Only Scan using gpointind on point_tbl p + Index Cond: (f1 |>> '(0,0)'::point) +(3 rows) + +SELECT count(*) FROM point_tbl p WHERE p.f1 |>> '(0.0, 0.0)'; + count +------- + 5 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)'; + QUERY PLAN +------------------------------------------------------ + Aggregate + -> Index Only Scan using gpointind on point_tbl p + Index Cond: (f1 ~= '(-5,-12)'::point) +(3 rows) + +SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)'; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT * FROM point_tbl ORDER BY f1 <-> '0,1'; + QUERY PLAN +---------------------------------------------- + Index Only Scan using gpointind on point_tbl + Order By: (f1 <-> '(0,1)'::point) +(2 rows) + +SELECT * FROM point_tbl ORDER BY f1 <-> '0,1'; + f1 +------------------- + (1e-300,-1e-300) + (0,0) + (-3,4) + (-10,0) + (10,10) + (-5,-12) + (5.1,34.5) + (Infinity,1e+300) + (1e+300,Infinity) + (NaN,NaN) + +(11 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM point_tbl WHERE f1 IS NULL; + QUERY PLAN +---------------------------------------------- + Index Only Scan using gpointind on point_tbl + Index Cond: (f1 IS NULL) +(2 rows) + +SELECT * FROM point_tbl WHERE f1 IS NULL; + f1 +---- + +(1 row) + +EXPLAIN (COSTS OFF) +SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1'; + QUERY PLAN +---------------------------------------------- + Index Only Scan using gpointind on point_tbl + Index Cond: (f1 IS NOT NULL) + Order By: (f1 <-> '(0,1)'::point) +(3 rows) + +SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1'; + f1 +------------------- + (1e-300,-1e-300) + (0,0) + (-3,4) + (-10,0) + (10,10) + (-5,-12) + (5.1,34.5) + (Infinity,1e+300) + (1e+300,Infinity) + (NaN,NaN) +(10 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; + QUERY PLAN +------------------------------------------------ + Index Only Scan using gpointind on point_tbl + Index Cond: (f1 <@ '(10,10),(-10,-10)'::box) + Order By: (f1 <-> '(0,1)'::point) +(3 rows) + +SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; + f1 +------------------ + (1e-300,-1e-300) + (0,0) + (-3,4) + (-10,0) + (10,10) +(5 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10; + QUERY PLAN +----------------------------------------------------- + Limit + -> Index Scan using ggpolygonind on gpolygon_tbl + Order By: (f1 <-> '(0,0)'::point) +(3 rows) + +SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10; + f1 +------------------------------------------------- + ((240,359),(240,455),(337,455),(337,359)) + ((662,163),(662,187),(759,187),(759,163)) + ((1000,0),(0,1000)) + ((0,1000),(1000,1000)) + ((1346,344),(1346,403),(1444,403),(1444,344)) + ((278,1409),(278,1457),(369,1457),(369,1409)) + ((907,1156),(907,1201),(948,1201),(948,1156)) + ((1517,971),(1517,1043),(1594,1043),(1594,971)) + ((175,1820),(175,1850),(259,1850),(259,1820)) + ((2424,81),(2424,160),(2424,160),(2424,81)) +(10 rows) + +EXPLAIN (COSTS OFF) +SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10; + QUERY PLAN +--------------------------------------------------- + Limit + -> Index Scan using ggcircleind on gcircle_tbl + Order By: (f1 <-> '(200,300)'::point) +(3 rows) + +SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10; + circle_center | radius +----------------+-------- + (288.5,407) | 68 + (710.5,175) | 50 + (323.5,1433) | 51 + (927.5,1178.5) | 30 + (1395,373.5) | 57 + (1555.5,1007) | 53 + (217,1835) | 45 + (489,2421.5) | 22 + (2424,120.5) | 40 + (751.5,2655) | 20 +(10 rows) + +EXPLAIN (COSTS OFF) +SELECT point(x,x), (SELECT f1 FROM gpolygon_tbl ORDER BY f1 <-> point(x,x) LIMIT 1) as c FROM generate_series(0,10,1) x; + QUERY PLAN +-------------------------------------------------------------------------------------------- + Function Scan on generate_series x + SubPlan 1 + -> Limit + -> Index Scan using ggpolygonind on gpolygon_tbl + Order By: (f1 <-> point((x.x)::double precision, (x.x)::double precision)) +(5 rows) + +SELECT point(x,x), (SELECT f1 FROM gpolygon_tbl ORDER BY f1 <-> point(x,x) LIMIT 1) as c FROM generate_series(0,10,1) x; + point | c +---------+------------------------------------------- + (0,0) | ((240,359),(240,455),(337,455),(337,359)) + (1,1) | ((240,359),(240,455),(337,455),(337,359)) + (2,2) | ((240,359),(240,455),(337,455),(337,359)) + (3,3) | ((240,359),(240,455),(337,455),(337,359)) + (4,4) | ((240,359),(240,455),(337,455),(337,359)) + (5,5) | ((240,359),(240,455),(337,455),(337,359)) + (6,6) | ((240,359),(240,455),(337,455),(337,359)) + (7,7) | ((240,359),(240,455),(337,455),(337,359)) + (8,8) | ((240,359),(240,455),(337,455),(337,359)) + (9,9) | ((240,359),(240,455),(337,455),(337,359)) + (10,10) | ((240,359),(240,455),(337,455),(337,359)) +(11 rows) + +-- Now check the results from bitmap indexscan +SET enable_seqscan = OFF; +SET enable_indexscan = OFF; +SET enable_bitmapscan = ON; +EXPLAIN (COSTS OFF) +SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; + QUERY PLAN +------------------------------------------------------------ + Sort + Sort Key: ((f1 <-> '(0,1)'::point)) + -> Bitmap Heap Scan on point_tbl + Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box) + -> Bitmap Index Scan on gpointind + Index Cond: (f1 <@ '(10,10),(-10,-10)'::box) +(6 rows) + +SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; + f1 +------------------ + (0,0) + (1e-300,-1e-300) + (-3,4) + (-10,0) + (10,10) +(5 rows) + +RESET enable_seqscan; +RESET enable_indexscan; +RESET enable_bitmapscan; +-- +-- GIN over int[] and text[] +-- +-- Note: GIN currently supports only bitmap scans, not plain indexscans +-- +CREATE TABLE array_index_op_test ( + seqno int4, + i int4[], + t text[] +); +\set filename :abs_srcdir '/data/array.data' +COPY array_index_op_test FROM :'filename'; +ANALYZE array_index_op_test; +SELECT * FROM array_index_op_test WHERE i = '{NULL}' ORDER BY seqno; + seqno | i | t +-------+--------+-------- + 102 | {NULL} | {NULL} +(1 row) + +SELECT * FROM array_index_op_test WHERE i @> '{NULL}' ORDER BY seqno; + seqno | i | t +-------+---+--- +(0 rows) + +SELECT * FROM array_index_op_test WHERE i && '{NULL}' ORDER BY seqno; + seqno | i | t +-------+---+--- +(0 rows) + +SELECT * FROM array_index_op_test WHERE i <@ '{NULL}' ORDER BY seqno; + seqno | i | t +-------+----+---- + 101 | {} | {} +(1 row) + +SET enable_seqscan = OFF; +SET enable_indexscan = OFF; +SET enable_bitmapscan = ON; +CREATE INDEX intarrayidx ON array_index_op_test USING gin (i); +explain (costs off) +SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno; + QUERY PLAN +---------------------------------------------------- + Sort + Sort Key: seqno + -> Bitmap Heap Scan on array_index_op_test + Recheck Cond: (i @> '{32}'::integer[]) + -> Bitmap Index Scan on intarrayidx + Index Cond: (i @> '{32}'::integer[]) +(6 rows) + +SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(6 rows) + +SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(6 rows) + +SELECT * FROM array_index_op_test WHERE i @> '{17}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} + 53 | {38,17} | {AAAAAAAAAAA21658} + 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} +(8 rows) + +SELECT * FROM array_index_op_test WHERE i && '{17}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} + 53 | {38,17} | {AAAAAAAAAAA21658} + 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} +(8 rows) + +SELECT * FROM array_index_op_test WHERE i @> '{32,17}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} +(3 rows) + +SELECT * FROM array_index_op_test WHERE i && '{32,17}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} + 53 | {38,17} | {AAAAAAAAAAA21658} + 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(11 rows) + +SELECT * FROM array_index_op_test WHERE i <@ '{38,34,32,89}' ORDER BY seqno; + seqno | i | t +-------+---------------+---------------------------------------------------------------------------------------------------------------------------- + 40 | {34} | {AAAAAAAAAAAAAA10611,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAA31334,AAAAA70466,AAAAAAAA81587,AAAAAAA74623} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 101 | {} | {} +(4 rows) + +SELECT * FROM array_index_op_test WHERE i = '{47,77}' ORDER BY seqno; + seqno | i | t +-------+---------+----------------------------------------------------------------------------------------------------------------- + 95 | {47,77} | {AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA74076,AAAAAAAAAA18107,AAAAA40681,AAAAAAAAAAAAAAA35875,AAAAA60038,AAAAAAA56483} +(1 row) + +SELECT * FROM array_index_op_test WHERE i = '{}' ORDER BY seqno; + seqno | i | t +-------+----+---- + 101 | {} | {} +(1 row) + +SELECT * FROM array_index_op_test WHERE i @> '{}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | {92,75,71,52,64,83} | {AAAAAAAA44066,AAAAAA1059,AAAAAAAAAAA176,AAAAAAA48038} + 2 | {3,6} | {AAAAAA98232,AAAAAAAA79710,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAAAAAAA55798,AAAAAAAAA12793} + 3 | {37,64,95,43,3,41,13,30,11,43} | {AAAAAAAAAA48845,AAAAA75968,AAAAA95309,AAA54451,AAAAAAAAAA22292,AAAAAAA99836,A96617,AA17009,AAAAAAAAAAAAAA95246} + 4 | {71,39,99,55,33,75,45} | {AAAAAAAAA53663,AAAAAAAAAAAAAAA67062,AAAAAAAAAA64777,AAA99043,AAAAAAAAAAAAAAAAAAA91804,39557} + 5 | {50,42,77,50,4} | {AAAAAAAAAAAAAAAAA26540,AAAAAAA79710,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA176,AAAAA95309,AAAAAAAAAAA46154,AAAAAA66777,AAAAAAAAA27249,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA70104} + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 7 | {12,51,88,64,8} | {AAAAAAAAAAAAAAAAAA12591,AAAAAAAAAAAAAAAAA50407,AAAAAAAAAAAA67946} + 8 | {60,84} | {AAAAAAA81898,AAAAAA1059,AAAAAAAAAAAA81511,AAAAA961,AAAAAAAAAAAAAAAA31334,AAAAA64741,AA6416,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAA50407} + 9 | {56,52,35,27,80,44,81,22} | {AAAAAAAAAAAAAAA73034,AAAAAAAAAAAAA7929,AAAAAAA66161,AA88409,39557,A27153,AAAAAAAA9523,AAAAAAAAAAA99000} + 10 | {71,5,45} | {AAAAAAAAAAA21658,AAAAAAAAAAAA21089,AAA54451,AAAAAAAAAAAAAAAAAA54141,AAAAAAAAAAAAAA28620,AAAAAAAAAAA21658,AAAAAAAAAAA74076,AAAAAAAAA27249} + 11 | {41,86,74,48,22,74,47,50} | {AAAAAAAA9523,AAAAAAAAAAAA37562,AAAAAAAAAAAAAAAA14047,AAAAAAAAAAA46154,AAAA41702,AAAAAAAAAAAAAAAAA764,AAAAA62737,39557} + 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} + 13 | {3,52,34,23} | {AAAAAA98232,AAAA49534,AAAAAAAAAAA21658} + 14 | {78,57,19} | {AAAA8857,AAAAAAAAAAAAAAA73034,AAAAAAAA81587,AAAAAAAAAAAAAAA68526,AAAAA75968,AAAAAAAAAAAAAA65909,AAAAAAAAA10012,AAAAAAAAAAAAAA65909} + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 16 | {14,63,85,11} | {AAAAAA66777} + 17 | {7,10,81,85} | {AAAAAA43678,AAAAAAA12144,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAAAAA15356} + 18 | {1} | {AAAAAAAAAAA33576,AAAAA95309,64261,AAA59323,AAAAAAAAAAAAAA95246,55847,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAAAA64374} + 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} + 20 | {72,89,70,51,54,37,8,49,79} | {AAAAAA58494} + 21 | {2,8,65,10,5,79,43} | {AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAAAAA91804,AAAAA64669,AAAAAAAAAAAAAAAA1443,AAAAAAAAAAAAAAAA23657,AAAAA12179,AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAA31334,AAAAAAAAAAAAAAAA41303,AAAAAAAAAAAAAAAAAAA85420} + 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} + 23 | {40,90,5,38,72,40,30,10,43,55} | {A6053,AAAAAAAAAAA6119,AA44673,AAAAAAAAAAAAAAAAA764,AA17009,AAAAA17383,AAAAA70514,AAAAA33250,AAAAA95309,AAAAAAAAAAAA37562} + 24 | {94,61,99,35,48} | {AAAAAAAAAAA50956,AAAAAAAAAAA15165,AAAA85070,AAAAAAAAAAAAAAA36627,AAAAA961,AAAAAAAAAA55219} + 25 | {31,1,10,11,27,79,38} | {AAAAAAAAAAAAAAAAAA59334,45449} + 26 | {71,10,9,69,75} | {47735,AAAAAAA21462,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA91804,AAAAAAAAA72121,AAAAAAAAAAAAAAAAAAA1205,AAAAA41597,AAAA8857,AAAAAAAAAAAAAAAAAAA15356,AA17009} + 27 | {94} | {AA6416,A6053,AAAAAAA21462,AAAAAAA57334,AAAAAAAAAAAAAAAAAA12591,AA88409,AAAAAAAAAAAAA70254} + 28 | {14,33,6,34,14} | {AAAAAAAAAAAAAAA13198,AAAAAAAA69452,AAAAAAAAAAA82945,AAAAAAA12144,AAAAAAAAA72121,AAAAAAAAAA18601} + 29 | {39,21} | {AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA38885,AAAA85070,AAAAAAAAAAAAAAAAAAA70104,AAAAA66674,AAAAAAAAAAAAA62007,AAAAAAAA69452,AAAAAAA1242,AAAAAAAAAAAAAAAA1729,AAAA35194} + 30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240} + 31 | {80,24,18,21,54} | {AAAAAAAAAAAAAAA13198,AAAAAAAAAAAAAAAAAAA70415,A27153,AAAAAAAAA53663,AAAAAAAAAAAAAAAAA50407,A68938} + 32 | {58,79,82,80,67,75,98,10,41} | {AAAAAAAAAAAAAAAAAA61286,AAA54451,AAAAAAAAAAAAAAAAAAA87527,A96617,51533} + 33 | {74,73} | {A85417,AAAAAAA56483,AAAAA17383,AAAAAAAAAAAAA62159,AAAAAAAAAAAA52814,AAAAAAAAAAAAA85723,AAAAAAAAAAAAAAAAAA55796} + 34 | {70,45} | {AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAA28620,AAAAAAAAAA55219,AAAAAAAA23648,AAAAAAAAAA22292,AAAAAAA1242} + 35 | {23,40} | {AAAAAAAAAAAA52814,AAAA48949,AAAAAAAAA34727,AAAA8857,AAAAAAAAAAAAAAAAAAA62179,AAAAAAAAAAAAAAA68526,AAAAAAA99836,AAAAAAAA50094,AAAA91194,AAAAAAAAAAAAA73084} + 36 | {79,82,14,52,30,5,79} | {AAAAAAAAA53663,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA89194,AA88409,AAAAAAAAAAAAAAA81326,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAA33598} + 37 | {53,11,81,39,3,78,58,64,74} | {AAAAAAAAAAAAAAAAAAA17075,AAAAAAA66161,AAAAAAAA23648,AAAAAAAAAAAAAA10611} + 38 | {59,5,4,95,28} | {AAAAAAAAAAA82945,A96617,47735,AAAAA12179,AAAAA64669,AAAAAA99807,AA74433,AAAAAAAAAAAAAAAAA59387} + 39 | {82,43,99,16,74} | {AAAAAAAAAAAAAAA67062,AAAAAAA57334,AAAAAAAAAAAAAA65909,A27153,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAA64777,AAAAAAAAAAAA81511,AAAAAAAAAAAAAA65909,AAAAAAAAAAAAAA28620} + 40 | {34} | {AAAAAAAAAAAAAA10611,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAA31334,AAAAA70466,AAAAAAAA81587,AAAAAAA74623} + 41 | {19,26,63,12,93,73,27,94} | {AAAAAAA79710,AAAAAAAAAA55219,AAAA41702,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAAAAA63050,AAAAAAA99836,AAAAAAAAAAAAAA8666} + 42 | {15,76,82,75,8,91} | {AAAAAAAAAAA176,AAAAAA38063,45449,AAAAAA54032,AAAAAAA81898,AA6416,AAAAAAAAAAAAAAAAAAA62179,45449,AAAAA60038,AAAAAAAA81587} + 43 | {39,87,91,97,79,28} | {AAAAAAAAAAA74076,A96617,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAAAAA55796,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAA67946} + 44 | {40,58,68,29,54} | {AAAAAAA81898,AAAAAA66777,AAAAAA98232} + 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} + 46 | {53,24} | {AAAAAAAAAAA53908,AAAAAA54032,AAAAA17383,AAAA48949,AAAAAAAAAA18601,AAAAA64669,45449,AAAAAAAAAAA98051,AAAAAAAAAAAAAAAAAA71621} + 47 | {98,23,64,12,75,61} | {AAA59323,AAAAA95309,AAAAAAAAAAAAAAAA31334,AAAAAAAAA27249,AAAAA17383,AAAAAAAAAAAA37562,AAAAAA1059,A84822,55847,AAAAA70466} + 48 | {76,14} | {AAAAAAAAAAAAA59671,AAAAAAAAAAAAAAAAAAA91804,AAAAAA66777,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAA73084,AAAAAAA79710,AAAAAAAAAAAAAAA40402,AAAAAAAAAAAAAAAAAAA65037} + 49 | {56,5,54,37,49} | {AA21643,AAAAAAAAAAA92631,AAAAAAAA81587} + 50 | {20,12,37,64,93} | {AAAAAAAAAA5483,AAAAAAAAAAAAAAAAAAA1205,AA6416,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAAAA47955} + 51 | {47} | {AAAAAAAAAAAAAA96505,AAAAAAAAAAAAAAAAAA36842,AAAAA95309,AAAAAAAA81587,AA6416,AAAA91194,AAAAAA58494,AAAAAA1059,AAAAAAAA69452} + 52 | {89,0} | {AAAAAAAAAAAAAAAAAA47955,AAAAAAA48038,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAA73084,AAAAA70466,AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA46154,AA66862} + 53 | {38,17} | {AAAAAAAAAAA21658} + 54 | {70,47} | {AAAAAAAAAAAAAAAAAA54141,AAAAA40681,AAAAAAA48038,AAAAAAAAAAAAAAAA29150,AAAAA41597,AAAAAAAAAAAAAAAAAA59334,AA15322} + 55 | {47,79,47,64,72,25,71,24,93} | {AAAAAAAAAAAAAAAAAA55796,AAAAA62737} + 56 | {33,7,60,54,93,90,77,85,39} | {AAAAAAAAAAAAAAAAAA32918,AA42406} + 57 | {23,45,10,42,36,21,9,96} | {AAAAAAAAAAAAAAAAAAA70415} + 58 | {92} | {AAAAAAAAAAAAAAAA98414,AAAAAAAA23648,AAAAAAAAAAAAAAAAAA55796,AA25381,AAAAAAAAAAA6119} + 59 | {9,69,46,77} | {39557,AAAAAAA89932,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAAAAAA26540,AAA20874,AA6416,AAAAAAAAAAAAAAAAAA47955} + 60 | {62,2,59,38,89} | {AAAAAAA89932,AAAAAAAAAAAAAAAAAAA15356,AA99927,AA17009,AAAAAAAAAAAAAAA35875} + 61 | {72,2,44,95,54,54,13} | {AAAAAAAAAAAAAAAAAAA91804} + 62 | {83,72,29,73} | {AAAAAAAAAAAAA15097,AAAA8857,AAAAAAAAAAAA35809,AAAAAAAAAAAA52814,AAAAAAAAAAAAAAAAAAA38885,AAAAAAAAAAAAAAAAAA24183,AAAAAA43678,A96617} + 63 | {11,4,61,87} | {AAAAAAAAA27249,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAA13198,AAA20874,39557,51533,AAAAAAAAAAA53908,AAAAAAAAAAAAAA96505,AAAAAAAA78938} + 64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240} + 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} + 66 | {31,23,70,52,4,33,48,25} | {AAAAAAAAAAAAAAAAA69675,AAAAAAAA50094,AAAAAAAAAAA92631,AAAA35194,39557,AAAAAAA99836} + 67 | {31,94,7,10} | {AAAAAA38063,A96617,AAAA35194,AAAAAAAAAAAA67946} + 68 | {90,43,38} | {AA75092,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAA92631,AAAAAAAAA10012,AAAAAAAAAAAAA7929,AA21643} + 69 | {67,35,99,85,72,86,44} | {AAAAAAAAAAAAAAAAAAA1205,AAAAAAAA50094,AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAAAAAAA47955} + 70 | {56,70,83} | {AAAA41702,AAAAAAAAAAA82945,AA21643,AAAAAAAAAAA99000,A27153,AA25381,AAAAAAAAAAAAAA96505,AAAAAAA1242} + 71 | {74,26} | {AAAAAAAAAAA50956,AA74433,AAAAAAA21462,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAA70254,AAAAAAAAAA43419,39557} + 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} + 73 | {88,25,96,78,65,15,29,19} | {AAA54451,AAAAAAAAA27249,AAAAAAA9228,AAAAAAAAAAAAAAA67062,AAAAAAAAAAAAAAAAAAA70415,AAAAA17383,AAAAAAAAAAAAAAAA33598} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 75 | {12,96,83,24,71,89,55} | {AAAA48949,AAAAAAAA29716,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAA29150,AAA28075,AAAAAAAAAAAAAAAAA43052} + 76 | {92,55,10,7} | {AAAAAAAAAAAAAAA67062} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 78 | {55,89,44,84,34} | {AAAAAAAAAAA6119,AAAAAAAAAAAAAA8666,AA99927,AA42406,AAAAAAA81898,AAAAAAA9228,AAAAAAAAAAA92631,AA21643,AAAAAAAAAAAAAA28620} + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} + 80 | {74,89,44,80,0} | {AAAA35194,AAAAAAAA79710,AAA20874,AAAAAAAAAAAAAAAAAAA70104,AAAAAAAAAAAAA73084,AAAAAAA57334,AAAAAAA9228,AAAAAAAAAAAAA62007} + 81 | {63,77,54,48,61,53,97} | {AAAAAAAAAAAAAAA81326,AAAAAAAAAA22292,AA25381,AAAAAAAAAAA74076,AAAAAAA81898,AAAAAAAAA72121} + 82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104} + 83 | {14,10} | {AAAAAAAAAA22292,AAAAAAAAAAAAA70254,AAAAAAAAAAA6119} + 84 | {11,83,35,13,96,94} | {AAAAA95309,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAAA24183} + 85 | {39,60} | {AAAAAAAAAAAAAAAA55798,AAAAAAAAAA22292,AAAAAAA66161,AAAAAAA21462,AAAAAAAAAAAAAAAAAA12591,55847,AAAAAA98232,AAAAAAAAAAA46154} + 86 | {33,81,72,74,45,36,82} | {AAAAAAAA81587,AAAAAAAAAAAAAA96505,45449,AAAA80176} + 87 | {57,27,50,12,97,68} | {AAAAAAAAAAAAAAAAA26540,AAAAAAAAA10012,AAAAAAAAAAAA35809,AAAAAAAAAAAAAAAA29150,AAAAAAAAAAA82945,AAAAAA66777,31228,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAA96505} + 88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} + 90 | {88,75} | {AAAAA60038,AAAAAAAA23648,AAAAAAAAAAA99000,AAAA41702,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAA68526} + 91 | {78} | {AAAAAAAAAAAAA62007,AAA99043} + 92 | {85,63,49,45} | {AAAAAAA89932,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA21089} + 93 | {11} | {AAAAAAAAAAA176,AAAAAAAAAAAAAA8666,AAAAAAAAAAAAAAA453,AAAAAAAAAAAAA85723,A68938,AAAAAAAAAAAAA9821,AAAAAAA48038,AAAAAAAAAAAAAAAAA59387,AA99927,AAAAA17383} + 94 | {98,9,85,62,88,91,60,61,38,86} | {AAAAAAAA81587,AAAAA17383,AAAAAAAA81587} + 95 | {47,77} | {AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA74076,AAAAAAAAAA18107,AAAAA40681,AAAAAAAAAAAAAAA35875,AAAAA60038,AAAAAAA56483} + 96 | {23,97,43} | {AAAAAAAAAA646,A87088} + 97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 99 | {37,86} | {AAAAAAAAAAAAAAAAAA32918,AAAAA70514,AAAAAAAAA10012,AAAAAAAAAAAAAAAAA59387,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA15356} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} + 101 | {} | {} + 102 | {NULL} | {NULL} +(102 rows) + +SELECT * FROM array_index_op_test WHERE i && '{}' ORDER BY seqno; + seqno | i | t +-------+---+--- +(0 rows) + +SELECT * FROM array_index_op_test WHERE i <@ '{}' ORDER BY seqno; + seqno | i | t +-------+----+---- + 101 | {} | {} +(1 row) + +CREATE INDEX textarrayidx ON array_index_op_test USING gin (t); +explain (costs off) +SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}' ORDER BY seqno; + QUERY PLAN +------------------------------------------------------------ + Sort + Sort Key: seqno + -> Bitmap Heap Scan on array_index_op_test + Recheck Cond: (t @> '{AAAAAAAA72908}'::text[]) + -> Bitmap Index Scan on textarrayidx + Index Cond: (t @> '{AAAAAAAA72908}'::text[]) +(6 rows) + +SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}' ORDER BY seqno; + seqno | i | t +-------+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------- + 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} + 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} + 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} +(4 rows) + +SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908}' ORDER BY seqno; + seqno | i | t +-------+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------- + 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} + 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} + 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} +(4 rows) + +SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAAAA646}' ORDER BY seqno; + seqno | i | t +-------+------------------+-------------------------------------------------------------------- + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} + 96 | {23,97,43} | {AAAAAAAAAA646,A87088} +(3 rows) + +SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAAAA646}' ORDER BY seqno; + seqno | i | t +-------+------------------+-------------------------------------------------------------------- + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} + 96 | {23,97,43} | {AAAAAAAAAA646,A87088} +(3 rows) + +SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908,AAAAAAAAAA646}' ORDER BY seqno; + seqno | i | t +-------+------+-------------------------------------------------------------------- + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} +(1 row) + +SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908,AAAAAAAAAA646}' ORDER BY seqno; + seqno | i | t +-------+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------- + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} + 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} + 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} + 96 | {23,97,43} | {AAAAAAAAAA646,A87088} +(6 rows) + +SELECT * FROM array_index_op_test WHERE t <@ '{AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611}' ORDER BY seqno; + seqno | i | t +-------+--------------------+----------------------------------------------------------------------------------------------------------- + 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} + 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} + 101 | {} | {} +(3 rows) + +SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}' ORDER BY seqno; + seqno | i | t +-------+------------+------------------------ + 96 | {23,97,43} | {AAAAAAAAAA646,A87088} +(1 row) + +SELECT * FROM array_index_op_test WHERE t = '{}' ORDER BY seqno; + seqno | i | t +-------+----+---- + 101 | {} | {} +(1 row) + +SELECT * FROM array_index_op_test WHERE t @> '{}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | {92,75,71,52,64,83} | {AAAAAAAA44066,AAAAAA1059,AAAAAAAAAAA176,AAAAAAA48038} + 2 | {3,6} | {AAAAAA98232,AAAAAAAA79710,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAAAAAAA55798,AAAAAAAAA12793} + 3 | {37,64,95,43,3,41,13,30,11,43} | {AAAAAAAAAA48845,AAAAA75968,AAAAA95309,AAA54451,AAAAAAAAAA22292,AAAAAAA99836,A96617,AA17009,AAAAAAAAAAAAAA95246} + 4 | {71,39,99,55,33,75,45} | {AAAAAAAAA53663,AAAAAAAAAAAAAAA67062,AAAAAAAAAA64777,AAA99043,AAAAAAAAAAAAAAAAAAA91804,39557} + 5 | {50,42,77,50,4} | {AAAAAAAAAAAAAAAAA26540,AAAAAAA79710,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA176,AAAAA95309,AAAAAAAAAAA46154,AAAAAA66777,AAAAAAAAA27249,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA70104} + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 7 | {12,51,88,64,8} | {AAAAAAAAAAAAAAAAAA12591,AAAAAAAAAAAAAAAAA50407,AAAAAAAAAAAA67946} + 8 | {60,84} | {AAAAAAA81898,AAAAAA1059,AAAAAAAAAAAA81511,AAAAA961,AAAAAAAAAAAAAAAA31334,AAAAA64741,AA6416,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAA50407} + 9 | {56,52,35,27,80,44,81,22} | {AAAAAAAAAAAAAAA73034,AAAAAAAAAAAAA7929,AAAAAAA66161,AA88409,39557,A27153,AAAAAAAA9523,AAAAAAAAAAA99000} + 10 | {71,5,45} | {AAAAAAAAAAA21658,AAAAAAAAAAAA21089,AAA54451,AAAAAAAAAAAAAAAAAA54141,AAAAAAAAAAAAAA28620,AAAAAAAAAAA21658,AAAAAAAAAAA74076,AAAAAAAAA27249} + 11 | {41,86,74,48,22,74,47,50} | {AAAAAAAA9523,AAAAAAAAAAAA37562,AAAAAAAAAAAAAAAA14047,AAAAAAAAAAA46154,AAAA41702,AAAAAAAAAAAAAAAAA764,AAAAA62737,39557} + 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} + 13 | {3,52,34,23} | {AAAAAA98232,AAAA49534,AAAAAAAAAAA21658} + 14 | {78,57,19} | {AAAA8857,AAAAAAAAAAAAAAA73034,AAAAAAAA81587,AAAAAAAAAAAAAAA68526,AAAAA75968,AAAAAAAAAAAAAA65909,AAAAAAAAA10012,AAAAAAAAAAAAAA65909} + 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} + 16 | {14,63,85,11} | {AAAAAA66777} + 17 | {7,10,81,85} | {AAAAAA43678,AAAAAAA12144,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAAAAA15356} + 18 | {1} | {AAAAAAAAAAA33576,AAAAA95309,64261,AAA59323,AAAAAAAAAAAAAA95246,55847,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAAAA64374} + 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} + 20 | {72,89,70,51,54,37,8,49,79} | {AAAAAA58494} + 21 | {2,8,65,10,5,79,43} | {AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAAAAA91804,AAAAA64669,AAAAAAAAAAAAAAAA1443,AAAAAAAAAAAAAAAA23657,AAAAA12179,AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAA31334,AAAAAAAAAAAAAAAA41303,AAAAAAAAAAAAAAAAAAA85420} + 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} + 23 | {40,90,5,38,72,40,30,10,43,55} | {A6053,AAAAAAAAAAA6119,AA44673,AAAAAAAAAAAAAAAAA764,AA17009,AAAAA17383,AAAAA70514,AAAAA33250,AAAAA95309,AAAAAAAAAAAA37562} + 24 | {94,61,99,35,48} | {AAAAAAAAAAA50956,AAAAAAAAAAA15165,AAAA85070,AAAAAAAAAAAAAAA36627,AAAAA961,AAAAAAAAAA55219} + 25 | {31,1,10,11,27,79,38} | {AAAAAAAAAAAAAAAAAA59334,45449} + 26 | {71,10,9,69,75} | {47735,AAAAAAA21462,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA91804,AAAAAAAAA72121,AAAAAAAAAAAAAAAAAAA1205,AAAAA41597,AAAA8857,AAAAAAAAAAAAAAAAAAA15356,AA17009} + 27 | {94} | {AA6416,A6053,AAAAAAA21462,AAAAAAA57334,AAAAAAAAAAAAAAAAAA12591,AA88409,AAAAAAAAAAAAA70254} + 28 | {14,33,6,34,14} | {AAAAAAAAAAAAAAA13198,AAAAAAAA69452,AAAAAAAAAAA82945,AAAAAAA12144,AAAAAAAAA72121,AAAAAAAAAA18601} + 29 | {39,21} | {AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA38885,AAAA85070,AAAAAAAAAAAAAAAAAAA70104,AAAAA66674,AAAAAAAAAAAAA62007,AAAAAAAA69452,AAAAAAA1242,AAAAAAAAAAAAAAAA1729,AAAA35194} + 30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240} + 31 | {80,24,18,21,54} | {AAAAAAAAAAAAAAA13198,AAAAAAAAAAAAAAAAAAA70415,A27153,AAAAAAAAA53663,AAAAAAAAAAAAAAAAA50407,A68938} + 32 | {58,79,82,80,67,75,98,10,41} | {AAAAAAAAAAAAAAAAAA61286,AAA54451,AAAAAAAAAAAAAAAAAAA87527,A96617,51533} + 33 | {74,73} | {A85417,AAAAAAA56483,AAAAA17383,AAAAAAAAAAAAA62159,AAAAAAAAAAAA52814,AAAAAAAAAAAAA85723,AAAAAAAAAAAAAAAAAA55796} + 34 | {70,45} | {AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAA28620,AAAAAAAAAA55219,AAAAAAAA23648,AAAAAAAAAA22292,AAAAAAA1242} + 35 | {23,40} | {AAAAAAAAAAAA52814,AAAA48949,AAAAAAAAA34727,AAAA8857,AAAAAAAAAAAAAAAAAAA62179,AAAAAAAAAAAAAAA68526,AAAAAAA99836,AAAAAAAA50094,AAAA91194,AAAAAAAAAAAAA73084} + 36 | {79,82,14,52,30,5,79} | {AAAAAAAAA53663,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA89194,AA88409,AAAAAAAAAAAAAAA81326,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAA33598} + 37 | {53,11,81,39,3,78,58,64,74} | {AAAAAAAAAAAAAAAAAAA17075,AAAAAAA66161,AAAAAAAA23648,AAAAAAAAAAAAAA10611} + 38 | {59,5,4,95,28} | {AAAAAAAAAAA82945,A96617,47735,AAAAA12179,AAAAA64669,AAAAAA99807,AA74433,AAAAAAAAAAAAAAAAA59387} + 39 | {82,43,99,16,74} | {AAAAAAAAAAAAAAA67062,AAAAAAA57334,AAAAAAAAAAAAAA65909,A27153,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAA64777,AAAAAAAAAAAA81511,AAAAAAAAAAAAAA65909,AAAAAAAAAAAAAA28620} + 40 | {34} | {AAAAAAAAAAAAAA10611,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAA31334,AAAAA70466,AAAAAAAA81587,AAAAAAA74623} + 41 | {19,26,63,12,93,73,27,94} | {AAAAAAA79710,AAAAAAAAAA55219,AAAA41702,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAAAAA63050,AAAAAAA99836,AAAAAAAAAAAAAA8666} + 42 | {15,76,82,75,8,91} | {AAAAAAAAAAA176,AAAAAA38063,45449,AAAAAA54032,AAAAAAA81898,AA6416,AAAAAAAAAAAAAAAAAAA62179,45449,AAAAA60038,AAAAAAAA81587} + 43 | {39,87,91,97,79,28} | {AAAAAAAAAAA74076,A96617,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAAAAA55796,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAA67946} + 44 | {40,58,68,29,54} | {AAAAAAA81898,AAAAAA66777,AAAAAA98232} + 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} + 46 | {53,24} | {AAAAAAAAAAA53908,AAAAAA54032,AAAAA17383,AAAA48949,AAAAAAAAAA18601,AAAAA64669,45449,AAAAAAAAAAA98051,AAAAAAAAAAAAAAAAAA71621} + 47 | {98,23,64,12,75,61} | {AAA59323,AAAAA95309,AAAAAAAAAAAAAAAA31334,AAAAAAAAA27249,AAAAA17383,AAAAAAAAAAAA37562,AAAAAA1059,A84822,55847,AAAAA70466} + 48 | {76,14} | {AAAAAAAAAAAAA59671,AAAAAAAAAAAAAAAAAAA91804,AAAAAA66777,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAA73084,AAAAAAA79710,AAAAAAAAAAAAAAA40402,AAAAAAAAAAAAAAAAAAA65037} + 49 | {56,5,54,37,49} | {AA21643,AAAAAAAAAAA92631,AAAAAAAA81587} + 50 | {20,12,37,64,93} | {AAAAAAAAAA5483,AAAAAAAAAAAAAAAAAAA1205,AA6416,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAAAA47955} + 51 | {47} | {AAAAAAAAAAAAAA96505,AAAAAAAAAAAAAAAAAA36842,AAAAA95309,AAAAAAAA81587,AA6416,AAAA91194,AAAAAA58494,AAAAAA1059,AAAAAAAA69452} + 52 | {89,0} | {AAAAAAAAAAAAAAAAAA47955,AAAAAAA48038,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAA73084,AAAAA70466,AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA46154,AA66862} + 53 | {38,17} | {AAAAAAAAAAA21658} + 54 | {70,47} | {AAAAAAAAAAAAAAAAAA54141,AAAAA40681,AAAAAAA48038,AAAAAAAAAAAAAAAA29150,AAAAA41597,AAAAAAAAAAAAAAAAAA59334,AA15322} + 55 | {47,79,47,64,72,25,71,24,93} | {AAAAAAAAAAAAAAAAAA55796,AAAAA62737} + 56 | {33,7,60,54,93,90,77,85,39} | {AAAAAAAAAAAAAAAAAA32918,AA42406} + 57 | {23,45,10,42,36,21,9,96} | {AAAAAAAAAAAAAAAAAAA70415} + 58 | {92} | {AAAAAAAAAAAAAAAA98414,AAAAAAAA23648,AAAAAAAAAAAAAAAAAA55796,AA25381,AAAAAAAAAAA6119} + 59 | {9,69,46,77} | {39557,AAAAAAA89932,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAAAAAA26540,AAA20874,AA6416,AAAAAAAAAAAAAAAAAA47955} + 60 | {62,2,59,38,89} | {AAAAAAA89932,AAAAAAAAAAAAAAAAAAA15356,AA99927,AA17009,AAAAAAAAAAAAAAA35875} + 61 | {72,2,44,95,54,54,13} | {AAAAAAAAAAAAAAAAAAA91804} + 62 | {83,72,29,73} | {AAAAAAAAAAAAA15097,AAAA8857,AAAAAAAAAAAA35809,AAAAAAAAAAAA52814,AAAAAAAAAAAAAAAAAAA38885,AAAAAAAAAAAAAAAAAA24183,AAAAAA43678,A96617} + 63 | {11,4,61,87} | {AAAAAAAAA27249,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAA13198,AAA20874,39557,51533,AAAAAAAAAAA53908,AAAAAAAAAAAAAA96505,AAAAAAAA78938} + 64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240} + 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} + 66 | {31,23,70,52,4,33,48,25} | {AAAAAAAAAAAAAAAAA69675,AAAAAAAA50094,AAAAAAAAAAA92631,AAAA35194,39557,AAAAAAA99836} + 67 | {31,94,7,10} | {AAAAAA38063,A96617,AAAA35194,AAAAAAAAAAAA67946} + 68 | {90,43,38} | {AA75092,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAA92631,AAAAAAAAA10012,AAAAAAAAAAAAA7929,AA21643} + 69 | {67,35,99,85,72,86,44} | {AAAAAAAAAAAAAAAAAAA1205,AAAAAAAA50094,AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAAAAAAA47955} + 70 | {56,70,83} | {AAAA41702,AAAAAAAAAAA82945,AA21643,AAAAAAAAAAA99000,A27153,AA25381,AAAAAAAAAAAAAA96505,AAAAAAA1242} + 71 | {74,26} | {AAAAAAAAAAA50956,AA74433,AAAAAAA21462,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAA70254,AAAAAAAAAA43419,39557} + 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} + 73 | {88,25,96,78,65,15,29,19} | {AAA54451,AAAAAAAAA27249,AAAAAAA9228,AAAAAAAAAAAAAAA67062,AAAAAAAAAAAAAAAAAAA70415,AAAAA17383,AAAAAAAAAAAAAAAA33598} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 75 | {12,96,83,24,71,89,55} | {AAAA48949,AAAAAAAA29716,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAA29150,AAA28075,AAAAAAAAAAAAAAAAA43052} + 76 | {92,55,10,7} | {AAAAAAAAAAAAAAA67062} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 78 | {55,89,44,84,34} | {AAAAAAAAAAA6119,AAAAAAAAAAAAAA8666,AA99927,AA42406,AAAAAAA81898,AAAAAAA9228,AAAAAAAAAAA92631,AA21643,AAAAAAAAAAAAAA28620} + 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} + 80 | {74,89,44,80,0} | {AAAA35194,AAAAAAAA79710,AAA20874,AAAAAAAAAAAAAAAAAAA70104,AAAAAAAAAAAAA73084,AAAAAAA57334,AAAAAAA9228,AAAAAAAAAAAAA62007} + 81 | {63,77,54,48,61,53,97} | {AAAAAAAAAAAAAAA81326,AAAAAAAAAA22292,AA25381,AAAAAAAAAAA74076,AAAAAAA81898,AAAAAAAAA72121} + 82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104} + 83 | {14,10} | {AAAAAAAAAA22292,AAAAAAAAAAAAA70254,AAAAAAAAAAA6119} + 84 | {11,83,35,13,96,94} | {AAAAA95309,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAAA24183} + 85 | {39,60} | {AAAAAAAAAAAAAAAA55798,AAAAAAAAAA22292,AAAAAAA66161,AAAAAAA21462,AAAAAAAAAAAAAAAAAA12591,55847,AAAAAA98232,AAAAAAAAAAA46154} + 86 | {33,81,72,74,45,36,82} | {AAAAAAAA81587,AAAAAAAAAAAAAA96505,45449,AAAA80176} + 87 | {57,27,50,12,97,68} | {AAAAAAAAAAAAAAAAA26540,AAAAAAAAA10012,AAAAAAAAAAAA35809,AAAAAAAAAAAAAAAA29150,AAAAAAAAAAA82945,AAAAAA66777,31228,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAA96505} + 88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} + 90 | {88,75} | {AAAAA60038,AAAAAAAA23648,AAAAAAAAAAA99000,AAAA41702,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAA68526} + 91 | {78} | {AAAAAAAAAAAAA62007,AAA99043} + 92 | {85,63,49,45} | {AAAAAAA89932,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA21089} + 93 | {11} | {AAAAAAAAAAA176,AAAAAAAAAAAAAA8666,AAAAAAAAAAAAAAA453,AAAAAAAAAAAAA85723,A68938,AAAAAAAAAAAAA9821,AAAAAAA48038,AAAAAAAAAAAAAAAAA59387,AA99927,AAAAA17383} + 94 | {98,9,85,62,88,91,60,61,38,86} | {AAAAAAAA81587,AAAAA17383,AAAAAAAA81587} + 95 | {47,77} | {AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA74076,AAAAAAAAAA18107,AAAAA40681,AAAAAAAAAAAAAAA35875,AAAAA60038,AAAAAAA56483} + 96 | {23,97,43} | {AAAAAAAAAA646,A87088} + 97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 99 | {37,86} | {AAAAAAAAAAAAAAAAAA32918,AAAAA70514,AAAAAAAAA10012,AAAAAAAAAAAAAAAAA59387,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA15356} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} + 101 | {} | {} + 102 | {NULL} | {NULL} +(102 rows) + +SELECT * FROM array_index_op_test WHERE t && '{}' ORDER BY seqno; + seqno | i | t +-------+---+--- +(0 rows) + +SELECT * FROM array_index_op_test WHERE t <@ '{}' ORDER BY seqno; + seqno | i | t +-------+----+---- + 101 | {} | {} +(1 row) + +-- And try it with a multicolumn GIN index +DROP INDEX intarrayidx, textarrayidx; +CREATE INDEX botharrayidx ON array_index_op_test USING gin (i, t); +SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(6 rows) + +SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno; + seqno | i | t +-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ + 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} + 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} + 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} + 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} + 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(6 rows) + +SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAA80240}' ORDER BY seqno; + seqno | i | t +-------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------- + 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} + 30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240} + 64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240} + 82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104} + 88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433} + 97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(7 rows) + +SELECT * FROM array_index_op_test WHERE t && '{AAAAAAA80240}' ORDER BY seqno; + seqno | i | t +-------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------- + 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} + 30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240} + 64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240} + 82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104} + 88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433} + 97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643} + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(7 rows) + +SELECT * FROM array_index_op_test WHERE i @> '{32}' AND t && '{AAAAAAA80240}' ORDER BY seqno; + seqno | i | t +-------+-----------------------------+------------------------------------------------------------------------------ + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(1 row) + +SELECT * FROM array_index_op_test WHERE i && '{32}' AND t @> '{AAAAAAA80240}' ORDER BY seqno; + seqno | i | t +-------+-----------------------------+------------------------------------------------------------------------------ + 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} +(1 row) + +SELECT * FROM array_index_op_test WHERE t = '{}' ORDER BY seqno; + seqno | i | t +-------+----+---- + 101 | {} | {} +(1 row) + +RESET enable_seqscan; +RESET enable_indexscan; +RESET enable_bitmapscan; +-- +-- Try a GIN index with a lot of items with same key. (GIN creates a posting +-- tree when there are enough duplicates) +-- +CREATE TABLE array_gin_test (a int[]); +INSERT INTO array_gin_test SELECT ARRAY[1, g%5, g] FROM generate_series(1, 10000) g; +CREATE INDEX array_gin_test_idx ON array_gin_test USING gin (a); +SELECT COUNT(*) FROM array_gin_test WHERE a @> '{2}'; + count +------- + 2000 +(1 row) + +DROP TABLE array_gin_test; +-- +-- Test GIN index's reloptions +-- +CREATE INDEX gin_relopts_test ON array_index_op_test USING gin (i) + WITH (FASTUPDATE=on, GIN_PENDING_LIST_LIMIT=128); +\d+ gin_relopts_test + Index "public.gin_relopts_test" + Column | Type | Key? | Definition | Storage | Stats target +--------+---------+------+------------+---------+-------------- + i | integer | yes | i | plain | +gin, for table "public.array_index_op_test" +Options: fastupdate=on, gin_pending_list_limit=128 + +-- +-- HASH +-- +CREATE UNLOGGED TABLE unlogged_hash_table (id int4); +CREATE INDEX unlogged_hash_index ON unlogged_hash_table USING hash (id int4_ops); +DROP TABLE unlogged_hash_table; +-- CREATE INDEX hash_ovfl_index ON hash_ovfl_heap USING hash (x int4_ops); +-- Test hash index build tuplesorting. Force hash tuplesort using low +-- maintenance_work_mem setting and fillfactor: +SET maintenance_work_mem = '1MB'; +CREATE INDEX hash_tuplesort_idx ON tenk1 USING hash (stringu1 name_ops) WITH (fillfactor = 10); +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 WHERE stringu1 = 'TVAAAA'; + QUERY PLAN +------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: (stringu1 = 'TVAAAA'::name) + -> Bitmap Index Scan on hash_tuplesort_idx + Index Cond: (stringu1 = 'TVAAAA'::name) +(5 rows) + +SELECT count(*) FROM tenk1 WHERE stringu1 = 'TVAAAA'; + count +------- + 14 +(1 row) + +-- OR-clauses shouldn't be transformed into SAOP because hash indexes don't +-- support SAOP scans. +SET enable_seqscan = off; +EXPLAIN (COSTS OFF) +SELECT COUNT(*) FROM tenk1 WHERE stringu1 = 'TVAAAA' OR stringu1 = 'TVAAAB'; + QUERY PLAN +------------------------------------------------------------------------------------ + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: ((stringu1 = 'TVAAAA'::name) OR (stringu1 = 'TVAAAB'::name)) + -> BitmapOr + -> Bitmap Index Scan on hash_tuplesort_idx + Index Cond: (stringu1 = 'TVAAAA'::name) + -> Bitmap Index Scan on hash_tuplesort_idx + Index Cond: (stringu1 = 'TVAAAB'::name) +(8 rows) + +RESET enable_seqscan; +DROP INDEX hash_tuplesort_idx; +RESET maintenance_work_mem; +-- +-- Test unique null behavior +-- +CREATE TABLE unique_tbl (i int, t text); +CREATE UNIQUE INDEX unique_idx1 ON unique_tbl (i) NULLS DISTINCT; +CREATE UNIQUE INDEX unique_idx2 ON unique_tbl (i) NULLS NOT DISTINCT; +INSERT INTO unique_tbl VALUES (1, 'one'); +INSERT INTO unique_tbl VALUES (2, 'two'); +INSERT INTO unique_tbl VALUES (3, 'three'); +INSERT INTO unique_tbl VALUES (4, 'four'); +INSERT INTO unique_tbl VALUES (5, 'one'); +INSERT INTO unique_tbl (t) VALUES ('six'); +INSERT INTO unique_tbl (t) VALUES ('seven'); -- error from unique_idx2 +ERROR: duplicate key value violates unique constraint "unique_idx2" +DETAIL: Key (i)=(null) already exists. +DROP INDEX unique_idx1, unique_idx2; +INSERT INTO unique_tbl (t) VALUES ('seven'); +-- build indexes on filled table +CREATE UNIQUE INDEX unique_idx3 ON unique_tbl (i) NULLS DISTINCT; -- ok +CREATE UNIQUE INDEX unique_idx4 ON unique_tbl (i) NULLS NOT DISTINCT; -- error +ERROR: could not create unique index "unique_idx4" +DETAIL: Key (i)=(null) is duplicated. +DELETE FROM unique_tbl WHERE t = 'seven'; +CREATE UNIQUE INDEX unique_idx4 ON unique_tbl (i) NULLS NOT DISTINCT; -- ok now +\d unique_tbl + Table "public.unique_tbl" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + i | integer | | | + t | text | | | +Indexes: + "unique_idx3" UNIQUE, btree (i) + "unique_idx4" UNIQUE, btree (i) NULLS NOT DISTINCT + +\d unique_idx3 + Index "public.unique_idx3" + Column | Type | Key? | Definition +--------+---------+------+------------ + i | integer | yes | i +unique, btree, for table "public.unique_tbl" + +\d unique_idx4 + Index "public.unique_idx4" + Column | Type | Key? | Definition +--------+---------+------+------------ + i | integer | yes | i +unique nulls not distinct, btree, for table "public.unique_tbl" + +SELECT pg_get_indexdef('unique_idx3'::regclass); + pg_get_indexdef +---------------------------------------------------------------------- + CREATE UNIQUE INDEX unique_idx3 ON public.unique_tbl USING btree (i) +(1 row) + +SELECT pg_get_indexdef('unique_idx4'::regclass); + pg_get_indexdef +----------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX unique_idx4 ON public.unique_tbl USING btree (i) NULLS NOT DISTINCT +(1 row) + +DROP TABLE unique_tbl; +-- +-- Test functional index +-- +CREATE TABLE func_index_heap (f1 text, f2 text); +CREATE UNIQUE INDEX func_index_index on func_index_heap (textcat(f1,f2)); +INSERT INTO func_index_heap VALUES('ABC','DEF'); +INSERT INTO func_index_heap VALUES('AB','CDEFG'); +INSERT INTO func_index_heap VALUES('QWE','RTY'); +-- this should fail because of unique index: +INSERT INTO func_index_heap VALUES('ABCD', 'EF'); +ERROR: duplicate key value violates unique constraint "func_index_index" +DETAIL: Key (textcat(f1, f2))=(ABCDEF) already exists. +-- but this shouldn't: +INSERT INTO func_index_heap VALUES('QWERTY'); +-- while we're here, see that the metadata looks sane +\d func_index_heap + Table "public.func_index_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | +Indexes: + "func_index_index" UNIQUE, btree (textcat(f1, f2)) + +\d func_index_index + Index "public.func_index_index" + Column | Type | Key? | Definition +---------+------+------+----------------- + textcat | text | yes | textcat(f1, f2) +unique, btree, for table "public.func_index_heap" + +-- +-- Same test, expressional index +-- +DROP TABLE func_index_heap; +CREATE TABLE func_index_heap (f1 text, f2 text); +CREATE UNIQUE INDEX func_index_index on func_index_heap ((f1 || f2) text_ops); +INSERT INTO func_index_heap VALUES('ABC','DEF'); +INSERT INTO func_index_heap VALUES('AB','CDEFG'); +INSERT INTO func_index_heap VALUES('QWE','RTY'); +-- this should fail because of unique index: +INSERT INTO func_index_heap VALUES('ABCD', 'EF'); +ERROR: duplicate key value violates unique constraint "func_index_index" +DETAIL: Key ((f1 || f2))=(ABCDEF) already exists. +-- but this shouldn't: +INSERT INTO func_index_heap VALUES('QWERTY'); +-- while we're here, see that the metadata looks sane +\d func_index_heap + Table "public.func_index_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | +Indexes: + "func_index_index" UNIQUE, btree ((f1 || f2)) + +\d func_index_index + Index "public.func_index_index" + Column | Type | Key? | Definition +--------+------+------+------------ + expr | text | yes | (f1 || f2) +unique, btree, for table "public.func_index_heap" + +-- this should fail because of unsafe column type (anonymous record) +create index on func_index_heap ((f1 || f2), (row(f1, f2))); +ERROR: column "row" has pseudo-type record +-- +-- Test unique index with included columns +-- +CREATE TABLE covering_index_heap (f1 int, f2 int, f3 text); +CREATE UNIQUE INDEX covering_index_index on covering_index_heap (f1,f2) INCLUDE(f3); +INSERT INTO covering_index_heap VALUES(1,1,'AAA'); +INSERT INTO covering_index_heap VALUES(1,2,'AAA'); +-- this should fail because of unique index on f1,f2: +INSERT INTO covering_index_heap VALUES(1,2,'BBB'); +ERROR: duplicate key value violates unique constraint "covering_index_index" +DETAIL: Key (f1, f2)=(1, 2) already exists. +-- and this shouldn't: +INSERT INTO covering_index_heap VALUES(1,4,'AAA'); +-- Try to build index on table that already contains data +CREATE UNIQUE INDEX covering_pkey on covering_index_heap (f1,f2) INCLUDE(f3); +-- Try to use existing covering index as primary key +ALTER TABLE covering_index_heap ADD CONSTRAINT covering_pkey PRIMARY KEY USING INDEX +covering_pkey; +DROP TABLE covering_index_heap; +-- +-- Try some concurrent index builds +-- +-- Unfortunately this only tests about half the code paths because there are +-- no concurrent updates happening to the table at the same time. +CREATE TABLE concur_heap (f1 text, f2 text); +-- empty table +CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1); +CREATE INDEX CONCURRENTLY IF NOT EXISTS concur_index1 ON concur_heap(f2,f1); +NOTICE: relation "concur_index1" already exists, skipping +INSERT INTO concur_heap VALUES ('a','b'); +INSERT INTO concur_heap VALUES ('b','b'); +-- unique index +CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1); +CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index2 ON concur_heap(f1); +NOTICE: relation "concur_index2" already exists, skipping +-- check if constraint is set up properly to be enforced +INSERT INTO concur_heap VALUES ('b','x'); +ERROR: duplicate key value violates unique constraint "concur_index2" +DETAIL: Key (f1)=(b) already exists. +-- check if constraint is enforced properly at build time +CREATE UNIQUE INDEX CONCURRENTLY concur_index3 ON concur_heap(f2); +ERROR: could not create unique index "concur_index3" +DETAIL: Key (f2)=(b) is duplicated. +-- test that expression indexes and partial indexes work concurrently +CREATE INDEX CONCURRENTLY concur_index4 on concur_heap(f2) WHERE f1='a'; +CREATE INDEX CONCURRENTLY concur_index5 on concur_heap(f2) WHERE f1='x'; +-- here we also check that you can default the index name +CREATE INDEX CONCURRENTLY on concur_heap((f2||f1)); +-- You can't do a concurrent index build in a transaction +BEGIN; +CREATE INDEX CONCURRENTLY concur_index7 ON concur_heap(f1); +ERROR: CREATE INDEX CONCURRENTLY cannot run inside a transaction block +COMMIT; +-- test where predicate is able to do a transactional update during +-- a concurrent build before switching pg_index state flags. +CREATE FUNCTION predicate_stable() RETURNS bool IMMUTABLE +LANGUAGE plpgsql AS $$ +BEGIN + EXECUTE 'SELECT txid_current()'; + RETURN true; +END; $$; +CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) + WHERE predicate_stable(); +DROP INDEX concur_index8; +DROP FUNCTION predicate_stable(); +-- But you can do a regular index build in a transaction +BEGIN; +CREATE INDEX std_index on concur_heap(f2); +COMMIT; +-- Failed builds are left invalid by VACUUM FULL, fixed by REINDEX +VACUUM FULL concur_heap; +REINDEX TABLE concur_heap; +ERROR: could not create unique index "concur_index3" +DETAIL: Key (f2)=(b) is duplicated. +DELETE FROM concur_heap WHERE f1 = 'b'; +VACUUM FULL concur_heap; +\d concur_heap + Table "public.concur_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | +Indexes: + "concur_heap_expr_idx" btree ((f2 || f1)) + "concur_index1" btree (f2, f1) + "concur_index2" UNIQUE, btree (f1) + "concur_index3" UNIQUE, btree (f2) INVALID + "concur_index4" btree (f2) WHERE f1 = 'a'::text + "concur_index5" btree (f2) WHERE f1 = 'x'::text + "std_index" btree (f2) + +REINDEX TABLE concur_heap; +\d concur_heap + Table "public.concur_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | +Indexes: + "concur_heap_expr_idx" btree ((f2 || f1)) + "concur_index1" btree (f2, f1) + "concur_index2" UNIQUE, btree (f1) + "concur_index3" UNIQUE, btree (f2) + "concur_index4" btree (f2) WHERE f1 = 'a'::text + "concur_index5" btree (f2) WHERE f1 = 'x'::text + "std_index" btree (f2) + +-- Temporary tables with concurrent builds and on-commit actions +-- CONCURRENTLY used with CREATE INDEX and DROP INDEX is ignored. +-- PRESERVE ROWS, the default. +CREATE TEMP TABLE concur_temp (f1 int, f2 text) + ON COMMIT PRESERVE ROWS; +INSERT INTO concur_temp VALUES (1, 'foo'), (2, 'bar'); +CREATE INDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); +DROP INDEX CONCURRENTLY concur_temp_ind; +DROP TABLE concur_temp; +-- ON COMMIT DROP +BEGIN; +CREATE TEMP TABLE concur_temp (f1 int, f2 text) + ON COMMIT DROP; +INSERT INTO concur_temp VALUES (1, 'foo'), (2, 'bar'); +-- Fails when running in a transaction. +CREATE INDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); +ERROR: CREATE INDEX CONCURRENTLY cannot run inside a transaction block +COMMIT; +-- ON COMMIT DELETE ROWS +CREATE TEMP TABLE concur_temp (f1 int, f2 text) + ON COMMIT DELETE ROWS; +INSERT INTO concur_temp VALUES (1, 'foo'), (2, 'bar'); +CREATE INDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); +DROP INDEX CONCURRENTLY concur_temp_ind; +DROP TABLE concur_temp; +-- +-- Try some concurrent index drops +-- +DROP INDEX CONCURRENTLY "concur_index2"; -- works +DROP INDEX CONCURRENTLY IF EXISTS "concur_index2"; -- notice +NOTICE: index "concur_index2" does not exist, skipping +-- failures +DROP INDEX CONCURRENTLY "concur_index2", "concur_index3"; +ERROR: DROP INDEX CONCURRENTLY does not support dropping multiple objects +BEGIN; +DROP INDEX CONCURRENTLY "concur_index5"; +ERROR: DROP INDEX CONCURRENTLY cannot run inside a transaction block +ROLLBACK; +-- successes +DROP INDEX CONCURRENTLY IF EXISTS "concur_index3"; +DROP INDEX CONCURRENTLY "concur_index4"; +DROP INDEX CONCURRENTLY "concur_index5"; +DROP INDEX CONCURRENTLY "concur_index1"; +DROP INDEX CONCURRENTLY "concur_heap_expr_idx"; +\d concur_heap + Table "public.concur_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | +Indexes: + "std_index" btree (f2) + +DROP TABLE concur_heap; +-- +-- Test ADD CONSTRAINT USING INDEX +-- +CREATE TABLE cwi_test( a int , b varchar(10), c char); +-- add some data so that all tests have something to work with. +INSERT INTO cwi_test VALUES(1, 2), (3, 4), (5, 6); +CREATE UNIQUE INDEX cwi_uniq_idx ON cwi_test(a , b); +ALTER TABLE cwi_test ADD primary key USING INDEX cwi_uniq_idx; +\d cwi_test + Table "public.cwi_test" + Column | Type | Collation | Nullable | Default +--------+-----------------------+-----------+----------+--------- + a | integer | | not null | + b | character varying(10) | | not null | + c | character(1) | | | +Indexes: + "cwi_uniq_idx" PRIMARY KEY, btree (a, b) + +\d cwi_uniq_idx + Index "public.cwi_uniq_idx" + Column | Type | Key? | Definition +--------+-----------------------+------+------------ + a | integer | yes | a + b | character varying(10) | yes | b +primary key, btree, for table "public.cwi_test" + +CREATE UNIQUE INDEX cwi_uniq2_idx ON cwi_test(b , a); +ALTER TABLE cwi_test DROP CONSTRAINT cwi_uniq_idx, + ADD CONSTRAINT cwi_replaced_pkey PRIMARY KEY + USING INDEX cwi_uniq2_idx; +NOTICE: ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index "cwi_uniq2_idx" to "cwi_replaced_pkey" +\d cwi_test + Table "public.cwi_test" + Column | Type | Collation | Nullable | Default +--------+-----------------------+-----------+----------+--------- + a | integer | | not null | + b | character varying(10) | | not null | + c | character(1) | | | +Indexes: + "cwi_replaced_pkey" PRIMARY KEY, btree (b, a) + +\d cwi_replaced_pkey + Index "public.cwi_replaced_pkey" + Column | Type | Key? | Definition +--------+-----------------------+------+------------ + b | character varying(10) | yes | b + a | integer | yes | a +primary key, btree, for table "public.cwi_test" + +DROP INDEX cwi_replaced_pkey; -- Should fail; a constraint depends on it +ERROR: cannot drop index cwi_replaced_pkey because constraint cwi_replaced_pkey on table cwi_test requires it +HINT: You can drop constraint cwi_replaced_pkey on table cwi_test instead. +-- Check that non-default index options are rejected +CREATE UNIQUE INDEX cwi_uniq3_idx ON cwi_test(a desc); +ALTER TABLE cwi_test ADD UNIQUE USING INDEX cwi_uniq3_idx; -- fail +ERROR: index "cwi_uniq3_idx" column number 1 does not have default sorting behavior +LINE 1: ALTER TABLE cwi_test ADD UNIQUE USING INDEX cwi_uniq3_idx; + ^ +DETAIL: Cannot create a primary key or unique constraint using such an index. +CREATE UNIQUE INDEX cwi_uniq4_idx ON cwi_test(b collate "POSIX"); +ALTER TABLE cwi_test ADD UNIQUE USING INDEX cwi_uniq4_idx; -- fail +ERROR: index "cwi_uniq4_idx" column number 1 does not have default sorting behavior +LINE 1: ALTER TABLE cwi_test ADD UNIQUE USING INDEX cwi_uniq4_idx; + ^ +DETAIL: Cannot create a primary key or unique constraint using such an index. +DROP TABLE cwi_test; +-- ADD CONSTRAINT USING INDEX is forbidden on partitioned tables +CREATE TABLE cwi_test(a int) PARTITION BY hash (a); +create unique index on cwi_test (a); +alter table cwi_test add primary key using index cwi_test_a_idx ; +ERROR: ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables +DROP TABLE cwi_test; +-- PRIMARY KEY constraint cannot be backed by a NULLS NOT DISTINCT index +CREATE TABLE cwi_test(a int, b int); +CREATE UNIQUE INDEX cwi_a_nnd ON cwi_test (a) NULLS NOT DISTINCT; +ALTER TABLE cwi_test ADD PRIMARY KEY USING INDEX cwi_a_nnd; +ERROR: primary keys cannot use NULLS NOT DISTINCT indexes +DROP TABLE cwi_test; +-- +-- Check handling of indexes on system columns +-- +CREATE TABLE syscol_table (a INT); +-- System columns cannot be indexed +CREATE INDEX ON syscol_table (ctid); +ERROR: index creation on system columns is not supported +-- nor used in expressions +CREATE INDEX ON syscol_table ((ctid >= '(1000,0)')); +ERROR: index creation on system columns is not supported +-- nor used in predicates +CREATE INDEX ON syscol_table (a) WHERE ctid >= '(1000,0)'; +ERROR: index creation on system columns is not supported +DROP TABLE syscol_table; +-- +-- Tests for IS NULL/IS NOT NULL with b-tree indexes +-- +CREATE TABLE onek_with_null AS SELECT unique1, unique2 FROM onek; +INSERT INTO onek_with_null(unique1, unique2) +VALUES (NULL, -1), (NULL, 2_147_483_647), (NULL, NULL), + (100, NULL), (500, NULL); +CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2,unique1); +SET enable_seqscan = OFF; +SET enable_indexscan = ON; +SET enable_bitmapscan = ON; +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL; + count +------- + 3 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL; + count +------- + 1 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL; + count +------- + 1002 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL; + count +------- + 2 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500; + count +------- + 499 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500; + count +------- + 0 +(1 row) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500 ORDER BY unique2 DESC, unique1 DESC LIMIT 1; + unique1 | unique2 +---------+--------- + 500 | +(1 row) + +DROP INDEX onek_nulltest; +CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2 desc,unique1); +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL; + count +------- + 3 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL; + count +------- + 1 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL; + count +------- + 1002 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL; + count +------- + 2 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500; + count +------- + 499 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500; + count +------- + 0 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IN (-1, 0, 1); + count +------- + 1 +(1 row) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500 ORDER BY unique2 DESC, unique1 DESC LIMIT 1; + unique1 | unique2 +---------+--------- + 500 | +(1 row) + +DROP INDEX onek_nulltest; +CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2 desc nulls last,unique1); +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL; + count +------- + 3 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL; + count +------- + 1 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL; + count +------- + 1002 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL; + count +------- + 2 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500; + count +------- + 499 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500; + count +------- + 0 +(1 row) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500 ORDER BY unique2 DESC, unique1 DESC LIMIT 1; + unique1 | unique2 +---------+--------- + 500 | +(1 row) + +DROP INDEX onek_nulltest; +CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2 nulls first,unique1); +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL; + count +------- + 3 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL; + count +------- + 1 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL; + count +------- + 1002 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL; + count +------- + 2 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500; + count +------- + 499 +(1 row) + +SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500; + count +------- + 0 +(1 row) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500 ORDER BY unique2 DESC, unique1 DESC LIMIT 1; + unique1 | unique2 +---------+--------- + 500 | +(1 row) + +DROP INDEX onek_nulltest; +-- Check initial-positioning logic too +CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2); +SET enable_seqscan = OFF; +SET enable_indexscan = ON; +SET enable_bitmapscan = OFF; +SELECT unique1, unique2 FROM onek_with_null + ORDER BY unique2 LIMIT 2; + unique1 | unique2 +---------+--------- + | -1 + 147 | 0 +(2 rows) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= -1 + ORDER BY unique2 LIMIT 2; + unique1 | unique2 +---------+--------- + | -1 + 147 | 0 +(2 rows) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= 0 + ORDER BY unique2 LIMIT 2; + unique1 | unique2 +---------+--------- + 147 | 0 + 931 | 1 +(2 rows) + +SELECT unique1, unique2 FROM onek_with_null + ORDER BY unique2 DESC LIMIT 5; + unique1 | unique2 +---------+------------ + 500 | + 100 | + | + | 2147483647 + 278 | 999 +(5 rows) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= -1 + ORDER BY unique2 DESC LIMIT 3; + unique1 | unique2 +---------+------------ + | 2147483647 + 278 | 999 + 0 | 998 +(3 rows) + +SELECT unique1, unique2 FROM onek_with_null WHERE unique2 < 999 + ORDER BY unique2 DESC LIMIT 2; + unique1 | unique2 +---------+--------- + 0 | 998 + 744 | 997 +(2 rows) + +RESET enable_seqscan; +RESET enable_indexscan; +RESET enable_bitmapscan; +DROP TABLE onek_with_null; +-- +-- Check bitmap index path planning +-- +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42 OR tenthous = 0); + QUERY PLAN +-------------------------------------------------------------------------------- + Index Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand = 42) AND (tenthous = ANY ('{1,3,42,0}'::integer[]))) +(2 rows) + +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42 OR tenthous = 0); + unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 +---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- + 42 | 5530 | 0 | 2 | 2 | 2 | 42 | 42 | 42 | 42 | 42 | 84 | 85 | QBAAAA | SEIAAA | OOOOxx +(1 row) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = (SELECT 1 + 2) OR tenthous = 42); + QUERY PLAN +---------------------------------------------------------------------------------------- + Index Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand = 42) AND (tenthous = ANY (ARRAY[1, (InitPlan 1).col1, 42]))) + InitPlan 1 + -> Result +(4 rows) + +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = (SELECT 1 + 2) OR tenthous = 42); + unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 +---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- + 42 | 5530 | 0 | 2 | 2 | 2 | 42 | 42 | 42 | 42 | 42 | 84 | 85 | QBAAAA | SEIAAA | OOOOxx +(1 row) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42 OR tenthous IS NULL); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- + Bitmap Heap Scan on tenk1 + Recheck Cond: (((thousand = 42) AND ((tenthous = 1) OR (tenthous = 3) OR (tenthous = 42))) OR ((thousand = 42) AND (tenthous IS NULL))) + Filter: ((tenthous = 1) OR (tenthous = 3) OR (tenthous = 42) OR (tenthous IS NULL)) + -> BitmapOr + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: ((thousand = 42) AND (tenthous = ANY ('{1,3,42}'::integer[]))) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: ((thousand = 42) AND (tenthous IS NULL)) +(8 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1::int2 OR tenthous::int2 = 3::int8 OR tenthous = 42::int8); + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Bitmap Heap Scan on tenk1 + Recheck Cond: (thousand = 42) + Filter: ((tenthous = '1'::smallint) OR ((tenthous)::smallint = '3'::bigint) OR (tenthous = '42'::bigint)) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = 42) +(5 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1::int2 OR tenthous::int2 = 3::int8 OR tenthous::int2 = 42::int8); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- + Bitmap Heap Scan on tenk1 + Recheck Cond: (thousand = 42) + Filter: ((tenthous = '1'::smallint) OR ((tenthous)::smallint = '3'::bigint) OR ((tenthous)::smallint = '42'::bigint)) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = 42) +(5 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1::int2 OR tenthous = 3::int8 OR tenthous = 42::int8); + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- + Bitmap Heap Scan on tenk1 + Recheck Cond: (((thousand = 42) AND (tenthous = '1'::smallint)) OR ((thousand = 42) AND ((tenthous = '3'::bigint) OR (tenthous = '42'::bigint)))) + Filter: ((tenthous = '1'::smallint) OR (tenthous = '3'::bigint) OR (tenthous = '42'::bigint)) + -> BitmapOr + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: ((thousand = 42) AND (tenthous = '1'::smallint)) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: ((thousand = 42) AND (tenthous = ANY ('{3,42}'::bigint[]))) +(8 rows) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); + QUERY PLAN +--------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: ((hundred = 42) AND ((thousand = 42) OR (thousand = 99))) + -> BitmapAnd + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred = 42) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = ANY ('{42,99}'::integer[])) +(8 rows) + +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); + count +------- + 10 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); + QUERY PLAN +------------------------------------------------------------------------------ + Index Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand = 42) AND (tenthous = ANY ('{1,3,42}'::integer[]))) +(2 rows) + +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); + unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 +---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- + 42 | 5530 | 0 | 2 | 2 | 2 | 42 | 42 | 42 | 42 | 42 | 84 | 85 | QBAAAA | SEIAAA | OOOOxx +(1 row) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1::numeric OR tenthous = 3::int4 OR tenthous = 42::numeric); + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Bitmap Heap Scan on tenk1 + Recheck Cond: (thousand = 42) + Filter: (((tenthous)::numeric = '1'::numeric) OR (tenthous = 3) OR ((tenthous)::numeric = '42'::numeric)) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = 42) +(5 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 + WHERE tenthous = 1::numeric OR tenthous = 3::int4 OR tenthous = 42::numeric; + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Seq Scan on tenk1 + Filter: (((tenthous)::numeric = '1'::numeric) OR (tenthous = 3) OR ((tenthous)::numeric = '42'::numeric)) +(2 rows) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 t1 + WHERE t1.thousand = 42 OR t1.thousand = (SELECT t2.tenthous FROM tenk1 t2 WHERE t2.thousand = t1.tenthous + 1 LIMIT 1); + QUERY PLAN +---------------------------------------------------------------------------- + Aggregate + -> Index Only Scan using tenk1_thous_tenthous on tenk1 t1 + Filter: ((thousand = 42) OR (thousand = (SubPlan 1))) + SubPlan 1 + -> Limit + -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2 + Index Cond: (thousand = (t1.tenthous + 1)) +(7 rows) + +SELECT count(*) FROM tenk1 t1 + WHERE t1.thousand = 42 OR t1.thousand = (SELECT t2.tenthous FROM tenk1 t2 WHERE t2.thousand = t1.tenthous + 1 LIMIT 1); + count +------- + 10 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); + QUERY PLAN +--------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: ((hundred = 42) AND ((thousand = 42) OR (thousand = 99))) + -> BitmapAnd + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred = 42) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = ANY ('{42,99}'::integer[])) +(8 rows) + +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); + count +------- + 10 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand < 42 OR thousand < 99 OR 43 > thousand OR 42 > thousand); + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: ((hundred = 42) AND ((thousand < 42) OR (thousand < 99) OR (43 > thousand) OR (42 > thousand))) + -> BitmapAnd + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred = 42) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand < ANY ('{42,99,43,42}'::integer[])) +(8 rows) + +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand < 42 OR thousand < 99 OR 43 > thousand OR 42 > thousand); + count +------- + 10 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41; + QUERY PLAN +----------------------------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: (((thousand = 42) AND ((tenthous = 1) OR (tenthous = 3))) OR (thousand = 41)) + -> BitmapOr + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: ((thousand = 42) AND (tenthous = ANY ('{1,3}'::integer[]))) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = 41) +(8 rows) + +SELECT count(*) FROM tenk1 + WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41; + count +------- + 10 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: (((hundred = 42) AND (((thousand = 42) OR (thousand = 99)) OR (tenthous < 2))) OR (thousand = 41)) + Filter: (((hundred = 42) AND ((thousand = 42) OR (thousand = 99) OR (tenthous < 2))) OR (thousand = 41)) + -> BitmapOr + -> BitmapAnd + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred = 42) + -> BitmapOr + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = ANY ('{42,99}'::integer[])) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (tenthous < 2) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = 41) +(15 rows) + +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41; + count +------- + 20 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on tenk1 + Recheck Cond: ((hundred = 42) AND (((thousand = 42) OR (thousand = 41)) OR ((thousand = 99) AND (tenthous = 2)))) + Filter: ((thousand = 42) OR (thousand = 41) OR ((thousand = 99) AND (tenthous = 2))) + -> BitmapAnd + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred = 42) + -> BitmapOr + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: (thousand = ANY ('{42,41}'::integer[])) + -> Bitmap Index Scan on tenk1_thous_tenthous + Index Cond: ((thousand = 99) AND (tenthous = 2)) +(12 rows) + +SELECT count(*) FROM tenk1 + WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2); + count +------- + 10 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1, tenk2 + WHERE tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk1.thousand = 41 OR tenk2.tenthous = 2) AND + tenk2.hundred = tenk1.hundred; + QUERY PLAN +----------------------------------------------------------------------------------------------- + Aggregate + -> Nested Loop + Join Filter: ((tenk2.thousand = 42) OR (tenk1.thousand = 41) OR (tenk2.tenthous = 2)) + -> Bitmap Heap Scan on tenk1 + Recheck Cond: (hundred = 42) + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred = 42) + -> Materialize + -> Bitmap Heap Scan on tenk2 + Recheck Cond: (hundred = 42) + -> Bitmap Index Scan on tenk2_hundred + Index Cond: (hundred = 42) +(12 rows) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1, tenk2 + WHERE tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk2.thousand = 41 OR tenk2.tenthous = 2) AND + tenk2.hundred = tenk1.hundred; + QUERY PLAN +------------------------------------------------------------------------------ + Aggregate + -> Nested Loop + -> Bitmap Heap Scan on tenk2 + Recheck Cond: (hundred = 42) + Filter: ((thousand = 42) OR (thousand = 41) OR (tenthous = 2)) + -> Bitmap Index Scan on tenk2_hundred + Index Cond: (hundred = 42) + -> Index Only Scan using tenk1_hundred on tenk1 + Index Cond: (hundred = 42) +(9 rows) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 JOIN tenk2 ON + tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk2.thousand = 41 OR tenk2.tenthous = 2) AND + tenk2.hundred = tenk1.hundred; + QUERY PLAN +------------------------------------------------------------------------------ + Aggregate + -> Nested Loop + -> Bitmap Heap Scan on tenk2 + Recheck Cond: (hundred = 42) + Filter: ((thousand = 42) OR (thousand = 41) OR (tenthous = 2)) + -> Bitmap Index Scan on tenk2_hundred + Index Cond: (hundred = 42) + -> Index Only Scan using tenk1_hundred on tenk1 + Index Cond: (hundred = 42) +(9 rows) + +EXPLAIN (COSTS OFF) +SELECT count(*) FROM tenk1 LEFT JOIN tenk2 ON + tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk2.thousand = 41 OR tenk2.tenthous = 2) AND + tenk2.hundred = tenk1.hundred; + QUERY PLAN +------------------------------------------------------------------------------------ + Aggregate + -> Nested Loop Left Join + Join Filter: (tenk1.hundred = 42) + -> Index Only Scan using tenk1_hundred on tenk1 + -> Memoize + Cache Key: tenk1.hundred + Cache Mode: logical + -> Index Scan using tenk2_hundred on tenk2 + Index Cond: (hundred = tenk1.hundred) + Filter: ((thousand = 42) OR (thousand = 41) OR (tenthous = 2)) +(10 rows) + +-- +-- Check behavior with duplicate index column contents +-- +CREATE TABLE dupindexcols AS + SELECT unique1 as id, stringu2::text as f1 FROM tenk1; +CREATE INDEX dupindexcols_i ON dupindexcols (f1, id, f1 text_pattern_ops); +ANALYZE dupindexcols; +EXPLAIN (COSTS OFF) + SELECT count(*) FROM dupindexcols + WHERE f1 BETWEEN 'WA' AND 'ZZZ' and id < 1000 and f1 ~<~ 'YX'; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on dupindexcols + Recheck Cond: ((f1 >= 'WA'::text) AND (f1 <= 'ZZZ'::text) AND (id < 1000) AND (f1 ~<~ 'YX'::text)) + -> Bitmap Index Scan on dupindexcols_i + Index Cond: ((f1 >= 'WA'::text) AND (f1 <= 'ZZZ'::text) AND (id < 1000) AND (f1 ~<~ 'YX'::text)) +(5 rows) + +SELECT count(*) FROM dupindexcols + WHERE f1 BETWEEN 'WA' AND 'ZZZ' and id < 1000 and f1 ~<~ 'YX'; + count +------- + 97 +(1 row) + +-- +-- Check that index scans with SAOP array and/or skip array indexquals +-- return rows in index order +-- +explain (costs off) +SELECT unique1 FROM tenk1 +WHERE unique1 IN (1,42,7) +ORDER BY unique1; + QUERY PLAN +------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: (unique1 = ANY ('{1,42,7}'::integer[])) +(2 rows) + +SELECT unique1 FROM tenk1 +WHERE unique1 IN (1,42,7) +ORDER BY unique1; + unique1 +--------- + 1 + 7 + 42 +(3 rows) + +-- Skip array on "thousand", SAOP array on "tenthous": +explain (costs off) +SELECT thousand, tenthous FROM tenk1 +WHERE thousand < 2 AND tenthous IN (1001,3000) +ORDER BY thousand; + QUERY PLAN +-------------------------------------------------------------------------------- + Index Only Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand < 2) AND (tenthous = ANY ('{1001,3000}'::integer[]))) +(2 rows) + +SELECT thousand, tenthous FROM tenk1 +WHERE thousand < 2 AND tenthous IN (1001,3000) +ORDER BY thousand; + thousand | tenthous +----------+---------- + 0 | 3000 + 1 | 1001 +(2 rows) + +-- Skip array on "thousand", SAOP array on "tenthous", backward scan: +explain (costs off) +SELECT thousand, tenthous FROM tenk1 +WHERE thousand < 2 AND tenthous IN (1001,3000) +ORDER BY thousand DESC, tenthous DESC; + QUERY PLAN +-------------------------------------------------------------------------------- + Index Only Scan Backward using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand < 2) AND (tenthous = ANY ('{1001,3000}'::integer[]))) +(2 rows) + +SELECT thousand, tenthous FROM tenk1 +WHERE thousand < 2 AND tenthous IN (1001,3000) +ORDER BY thousand DESC, tenthous DESC; + thousand | tenthous +----------+---------- + 1 | 1001 + 0 | 3000 +(2 rows) + +explain (costs off) +SELECT thousand, tenthous FROM tenk1 +WHERE thousand > 995 and tenthous in (998, 999) +ORDER BY thousand desc; + QUERY PLAN +-------------------------------------------------------------------------------- + Index Only Scan Backward using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand > 995) AND (tenthous = ANY ('{998,999}'::integer[]))) +(2 rows) + +SELECT thousand, tenthous FROM tenk1 +WHERE thousand > 995 and tenthous in (998, 999) +ORDER BY thousand desc; + thousand | tenthous +----------+---------- + 999 | 999 + 998 | 998 +(2 rows) + +-- +-- Check elimination of redundant and contradictory index quals +-- +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = ANY('{7, 8, 9}'); + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 = ANY ('{7,8,9}'::integer[]))) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = ANY('{7, 8, 9}'); + unique1 +--------- + 7 +(1 row) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{7, 14, 22}') and unique1 = ANY('{33, 44}'::bigint[]); + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 = ANY ('{7,14,22}'::integer[])) AND (unique1 = ANY ('{33,44}'::bigint[]))) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{7, 14, 22}') and unique1 = ANY('{33, 44}'::bigint[]); + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 = ANY(NULL); + QUERY PLAN +------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: (unique1 = ANY (NULL::integer[])) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 = ANY(NULL); + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{NULL,NULL,NULL}'); + QUERY PLAN +--------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: (unique1 = ANY ('{NULL,NULL,NULL}'::integer[])) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{NULL,NULL,NULL}'); + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 IS NULL AND unique1 IS NULL; + QUERY PLAN +--------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 IS NULL) AND (unique1 IS NULL)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 IS NULL AND unique1 IS NULL; + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 1; + QUERY PLAN +--------------------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 = 1)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 1; + unique1 +--------- + 1 +(1 row) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 12345; + QUERY PLAN +------------------------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 = 12345)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 12345; + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 >= 42; + QUERY PLAN +----------------------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 >= 42)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 >= 42; + unique1 +--------- + 42 +(1 row) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 > 42; + QUERY PLAN +---------------------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 > 42)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 > 42; + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 > 9996 and unique1 >= 9999; + QUERY PLAN +-------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 > 9996) AND (unique1 >= 9999)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 > 9996 and unique1 >= 9999; + unique1 +--------- + 9999 +(1 row) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 < 3 and unique1 <= 3; + QUERY PLAN +-------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 < 3) AND (unique1 <= 3)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 < 3 and unique1 <= 3; + unique1 +--------- + 0 + 1 + 2 +(3 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 < 3 and unique1 < (-1)::bigint; + QUERY PLAN +------------------------------------------------------------ + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 < 3) AND (unique1 < '-1'::bigint)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 < 3 and unique1 < (-1)::bigint; + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 < (-1)::bigint; + QUERY PLAN +-------------------------------------------------------------------------------------- + Index Only Scan using tenk1_unique1 on tenk1 + Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 < '-1'::bigint)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 < (-1)::bigint; + unique1 +--------- +(0 rows) + +explain (costs off) +SELECT unique1 FROM tenk1 WHERE (thousand, tenthous) > (NULL, 5); + QUERY PLAN +----------------------------------------------------------------- + Index Scan using tenk1_thous_tenthous on tenk1 + Index Cond: (ROW(thousand, tenthous) > ROW(NULL::integer, 5)) +(2 rows) + +SELECT unique1 FROM tenk1 WHERE (thousand, tenthous) > (NULL, 5); + unique1 +--------- +(0 rows) + +-- Skip array redundancy (pair of redundant low_compare inequalities) +explain (costs off) +SELECT thousand, tenthous FROM tenk1 +WHERE thousand > -1 and thousand >= 0 AND tenthous = 3000 +ORDER BY thousand; + QUERY PLAN +-------------------------------------------------------------------------------------- + Index Only Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand > '-1'::integer) AND (thousand >= 0) AND (tenthous = 3000)) +(2 rows) + +SELECT thousand, tenthous FROM tenk1 +WHERE thousand > -1 and thousand >= 0 AND tenthous = 3000 +ORDER BY thousand; + thousand | tenthous +----------+---------- + 0 | 3000 +(1 row) + +-- Skip array redundancy (pair of redundant high_compare inequalities) +explain (costs off) +SELECT thousand, tenthous FROM tenk1 +WHERE thousand < 3 and thousand <= 2 AND tenthous = 1001 +ORDER BY thousand; + QUERY PLAN +-------------------------------------------------------------------------- + Index Only Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand < 3) AND (thousand <= 2) AND (tenthous = 1001)) +(2 rows) + +SELECT thousand, tenthous FROM tenk1 +WHERE thousand < 3 and thousand <= 2 AND tenthous = 1001 +ORDER BY thousand; + thousand | tenthous +----------+---------- + 1 | 1001 +(1 row) + +-- Skip array preprocessing increments "thousand > -1" to "thousand >= 0" +explain (costs off) +SELECT thousand, tenthous FROM tenk1 +WHERE thousand > -1 AND tenthous IN (1001,3000) +ORDER BY thousand limit 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------- + Limit + -> Index Only Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand > '-1'::integer) AND (tenthous = ANY ('{1001,3000}'::integer[]))) +(3 rows) + +SELECT thousand, tenthous FROM tenk1 +WHERE thousand > -1 AND tenthous IN (1001,3000) +ORDER BY thousand limit 2; + thousand | tenthous +----------+---------- + 0 | 3000 + 1 | 1001 +(2 rows) + +-- +-- Check elimination of constant-NULL subexpressions +-- +explain (costs off) + select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null)); + QUERY PLAN +------------------------------------------------------ + Index Scan using tenk1_thous_tenthous on tenk1 + Index Cond: ((thousand = 1) AND (tenthous = 1001)) +(2 rows) + +-- +-- Check matching of boolean index columns to WHERE conditions and sort keys +-- +create temp table boolindex (b bool, i int, unique(b, i), junk float); +explain (costs off) + select * from boolindex order by b, i limit 10; + QUERY PLAN +------------------------------------------------------- + Limit + -> Index Scan using boolindex_b_i_key on boolindex +(2 rows) + +explain (costs off) + select * from boolindex where b order by i limit 10; + QUERY PLAN +------------------------------------------------------- + Limit + -> Index Scan using boolindex_b_i_key on boolindex + Index Cond: (b = true) +(3 rows) + +explain (costs off) + select * from boolindex where b = true order by i desc limit 10; + QUERY PLAN +---------------------------------------------------------------- + Limit + -> Index Scan Backward using boolindex_b_i_key on boolindex + Index Cond: (b = true) +(3 rows) + +explain (costs off) + select * from boolindex where not b order by i limit 10; + QUERY PLAN +------------------------------------------------------- + Limit + -> Index Scan using boolindex_b_i_key on boolindex + Index Cond: (b = false) +(3 rows) + +explain (costs off) + select * from boolindex where b is true order by i desc limit 10; + QUERY PLAN +---------------------------------------------------------------- + Limit + -> Index Scan Backward using boolindex_b_i_key on boolindex + Index Cond: (b = true) +(3 rows) + +explain (costs off) + select * from boolindex where b is false order by i desc limit 10; + QUERY PLAN +---------------------------------------------------------------- + Limit + -> Index Scan Backward using boolindex_b_i_key on boolindex + Index Cond: (b = false) +(3 rows) + +-- +-- REINDEX (VERBOSE) +-- +CREATE TABLE reindex_verbose(id integer primary key); +\set VERBOSITY terse \\ -- suppress machine-dependent details +REINDEX (VERBOSE) TABLE reindex_verbose; +INFO: index "reindex_verbose_pkey" was reindexed +\set VERBOSITY default +DROP TABLE reindex_verbose; +-- +-- REINDEX CONCURRENTLY +-- +CREATE TABLE concur_reindex_tab (c1 int); +-- REINDEX +REINDEX TABLE concur_reindex_tab; -- notice +NOTICE: table "concur_reindex_tab" has no indexes to reindex +REINDEX (CONCURRENTLY) TABLE concur_reindex_tab; -- notice +NOTICE: table "concur_reindex_tab" has no indexes that can be reindexed concurrently +ALTER TABLE concur_reindex_tab ADD COLUMN c2 text; -- add toast index +-- Normal index with integer column +CREATE UNIQUE INDEX concur_reindex_ind1 ON concur_reindex_tab(c1); +-- Normal index with text column +CREATE INDEX concur_reindex_ind2 ON concur_reindex_tab(c2); +-- UNIQUE index with expression +CREATE UNIQUE INDEX concur_reindex_ind3 ON concur_reindex_tab(abs(c1)); +-- Duplicate column names +CREATE INDEX concur_reindex_ind4 ON concur_reindex_tab(c1, c1, c2); +-- Create table for check on foreign key dependence switch with indexes swapped +ALTER TABLE concur_reindex_tab ADD PRIMARY KEY USING INDEX concur_reindex_ind1; +CREATE TABLE concur_reindex_tab2 (c1 int REFERENCES concur_reindex_tab); +INSERT INTO concur_reindex_tab VALUES (1, 'a'); +INSERT INTO concur_reindex_tab VALUES (2, 'a'); +-- Reindex concurrently of exclusion constraint currently not supported +CREATE TABLE concur_reindex_tab3 (c1 int, c2 int4range, EXCLUDE USING gist (c2 WITH &&)); +INSERT INTO concur_reindex_tab3 VALUES (3, '[1,2]'); +REINDEX INDEX CONCURRENTLY concur_reindex_tab3_c2_excl; -- error +ERROR: concurrent index creation for exclusion constraints is not supported +REINDEX TABLE CONCURRENTLY concur_reindex_tab3; -- succeeds with warning +WARNING: cannot reindex exclusion constraint index "public.concur_reindex_tab3_c2_excl" concurrently, skipping +INSERT INTO concur_reindex_tab3 VALUES (4, '[2,4]'); +ERROR: conflicting key value violates exclusion constraint "concur_reindex_tab3_c2_excl" +DETAIL: Key (c2)=([2,5)) conflicts with existing key (c2)=([1,3)). +-- Check materialized views +CREATE MATERIALIZED VIEW concur_reindex_matview AS SELECT * FROM concur_reindex_tab; +-- Dependency lookup before and after the follow-up REINDEX commands. +-- These should remain consistent. +SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_describe_object(refclassid,refobjid,refobjsubid) as objref, + deptype +FROM pg_depend +WHERE classid = 'pg_class'::regclass AND + objid in ('concur_reindex_tab'::regclass, + 'concur_reindex_ind1'::regclass, + 'concur_reindex_ind2'::regclass, + 'concur_reindex_ind3'::regclass, + 'concur_reindex_ind4'::regclass, + 'concur_reindex_matview'::regclass) + ORDER BY 1, 2; + obj | objref | deptype +------------------------------------------+------------------------------------------------------------+--------- + index concur_reindex_ind1 | constraint concur_reindex_ind1 on table concur_reindex_tab | i + index concur_reindex_ind2 | column c2 of table concur_reindex_tab | a + index concur_reindex_ind3 | column c1 of table concur_reindex_tab | a + index concur_reindex_ind3 | table concur_reindex_tab | a + index concur_reindex_ind4 | column c1 of table concur_reindex_tab | a + index concur_reindex_ind4 | column c2 of table concur_reindex_tab | a + materialized view concur_reindex_matview | access method tde_heap | n + materialized view concur_reindex_matview | schema public | n + table concur_reindex_tab | access method tde_heap | n + table concur_reindex_tab | schema public | n +(10 rows) + +REINDEX INDEX CONCURRENTLY concur_reindex_ind1; +REINDEX TABLE CONCURRENTLY concur_reindex_tab; +REINDEX TABLE CONCURRENTLY concur_reindex_matview; +SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_describe_object(refclassid,refobjid,refobjsubid) as objref, + deptype +FROM pg_depend +WHERE classid = 'pg_class'::regclass AND + objid in ('concur_reindex_tab'::regclass, + 'concur_reindex_ind1'::regclass, + 'concur_reindex_ind2'::regclass, + 'concur_reindex_ind3'::regclass, + 'concur_reindex_ind4'::regclass, + 'concur_reindex_matview'::regclass) + ORDER BY 1, 2; + obj | objref | deptype +------------------------------------------+------------------------------------------------------------+--------- + index concur_reindex_ind1 | constraint concur_reindex_ind1 on table concur_reindex_tab | i + index concur_reindex_ind2 | column c2 of table concur_reindex_tab | a + index concur_reindex_ind3 | column c1 of table concur_reindex_tab | a + index concur_reindex_ind3 | table concur_reindex_tab | a + index concur_reindex_ind4 | column c1 of table concur_reindex_tab | a + index concur_reindex_ind4 | column c2 of table concur_reindex_tab | a + materialized view concur_reindex_matview | access method tde_heap | n + materialized view concur_reindex_matview | schema public | n + table concur_reindex_tab | access method tde_heap | n + table concur_reindex_tab | schema public | n +(10 rows) + +-- Check that comments are preserved +CREATE TABLE testcomment (i int); +CREATE INDEX testcomment_idx1 ON testcomment (i); +COMMENT ON INDEX testcomment_idx1 IS 'test comment'; +SELECT obj_description('testcomment_idx1'::regclass, 'pg_class'); + obj_description +----------------- + test comment +(1 row) + +REINDEX TABLE testcomment; +SELECT obj_description('testcomment_idx1'::regclass, 'pg_class'); + obj_description +----------------- + test comment +(1 row) + +REINDEX TABLE CONCURRENTLY testcomment ; +SELECT obj_description('testcomment_idx1'::regclass, 'pg_class'); + obj_description +----------------- + test comment +(1 row) + +DROP TABLE testcomment; +-- Check that indisclustered updates are preserved +CREATE TABLE concur_clustered(i int); +CREATE INDEX concur_clustered_i_idx ON concur_clustered(i); +ALTER TABLE concur_clustered CLUSTER ON concur_clustered_i_idx; +REINDEX TABLE CONCURRENTLY concur_clustered; +SELECT indexrelid::regclass, indisclustered FROM pg_index + WHERE indrelid = 'concur_clustered'::regclass; + indexrelid | indisclustered +------------------------+---------------- + concur_clustered_i_idx | t +(1 row) + +DROP TABLE concur_clustered; +-- Check that indisreplident updates are preserved. +CREATE TABLE concur_replident(i int NOT NULL); +CREATE UNIQUE INDEX concur_replident_i_idx ON concur_replident(i); +ALTER TABLE concur_replident REPLICA IDENTITY + USING INDEX concur_replident_i_idx; +SELECT indexrelid::regclass, indisreplident FROM pg_index + WHERE indrelid = 'concur_replident'::regclass; + indexrelid | indisreplident +------------------------+---------------- + concur_replident_i_idx | t +(1 row) + +REINDEX TABLE CONCURRENTLY concur_replident; +SELECT indexrelid::regclass, indisreplident FROM pg_index + WHERE indrelid = 'concur_replident'::regclass; + indexrelid | indisreplident +------------------------+---------------- + concur_replident_i_idx | t +(1 row) + +DROP TABLE concur_replident; +-- Check that opclass parameters are preserved +CREATE TABLE concur_appclass_tab(i tsvector, j tsvector, k tsvector); +CREATE INDEX concur_appclass_ind on concur_appclass_tab + USING gist (i tsvector_ops (siglen='1000'), j tsvector_ops (siglen='500')); +CREATE INDEX concur_appclass_ind_2 on concur_appclass_tab + USING gist (k tsvector_ops (siglen='300'), j tsvector_ops); +REINDEX TABLE CONCURRENTLY concur_appclass_tab; +\d concur_appclass_tab + Table "public.concur_appclass_tab" + Column | Type | Collation | Nullable | Default +--------+----------+-----------+----------+--------- + i | tsvector | | | + j | tsvector | | | + k | tsvector | | | +Indexes: + "concur_appclass_ind" gist (i tsvector_ops (siglen='1000'), j tsvector_ops (siglen='500')) + "concur_appclass_ind_2" gist (k tsvector_ops (siglen='300'), j) + +DROP TABLE concur_appclass_tab; +-- Partitions +-- Create some partitioned tables +CREATE TABLE concur_reindex_part (c1 int, c2 int) PARTITION BY RANGE (c1); +CREATE TABLE concur_reindex_part_0 PARTITION OF concur_reindex_part + FOR VALUES FROM (0) TO (10) PARTITION BY list (c2); +CREATE TABLE concur_reindex_part_0_1 PARTITION OF concur_reindex_part_0 + FOR VALUES IN (1); +CREATE TABLE concur_reindex_part_0_2 PARTITION OF concur_reindex_part_0 + FOR VALUES IN (2); +-- This partitioned table will have no partitions. +CREATE TABLE concur_reindex_part_10 PARTITION OF concur_reindex_part + FOR VALUES FROM (10) TO (20) PARTITION BY list (c2); +-- Create some partitioned indexes +CREATE INDEX concur_reindex_part_index ON ONLY concur_reindex_part (c1); +CREATE INDEX concur_reindex_part_index_0 ON ONLY concur_reindex_part_0 (c1); +ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_0; +-- This partitioned index will have no partitions. +CREATE INDEX concur_reindex_part_index_10 ON ONLY concur_reindex_part_10 (c1); +ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_10; +CREATE INDEX concur_reindex_part_index_0_1 ON ONLY concur_reindex_part_0_1 (c1); +ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_1; +CREATE INDEX concur_reindex_part_index_0_2 ON ONLY concur_reindex_part_0_2 (c1); +ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +-- REINDEX should preserve dependencies of partition tree. +SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_describe_object(refclassid,refobjid,refobjsubid) as objref, + deptype +FROM pg_depend +WHERE classid = 'pg_class'::regclass AND + objid in ('concur_reindex_part'::regclass, + 'concur_reindex_part_0'::regclass, + 'concur_reindex_part_0_1'::regclass, + 'concur_reindex_part_0_2'::regclass, + 'concur_reindex_part_index'::regclass, + 'concur_reindex_part_index_0'::regclass, + 'concur_reindex_part_index_0_1'::regclass, + 'concur_reindex_part_index_0_2'::regclass) + ORDER BY 1, 2; + obj | objref | deptype +------------------------------------------+--------------------------------------------+--------- + column c1 of table concur_reindex_part | table concur_reindex_part | i + column c2 of table concur_reindex_part_0 | table concur_reindex_part_0 | i + index concur_reindex_part_index | column c1 of table concur_reindex_part | a + index concur_reindex_part_index_0 | column c1 of table concur_reindex_part_0 | a + index concur_reindex_part_index_0 | index concur_reindex_part_index | P + index concur_reindex_part_index_0 | table concur_reindex_part_0 | S + index concur_reindex_part_index_0_1 | column c1 of table concur_reindex_part_0_1 | a + index concur_reindex_part_index_0_1 | index concur_reindex_part_index_0 | P + index concur_reindex_part_index_0_1 | table concur_reindex_part_0_1 | S + index concur_reindex_part_index_0_2 | column c1 of table concur_reindex_part_0_2 | a + index concur_reindex_part_index_0_2 | index concur_reindex_part_index_0 | P + index concur_reindex_part_index_0_2 | table concur_reindex_part_0_2 | S + table concur_reindex_part | schema public | n + table concur_reindex_part_0 | schema public | n + table concur_reindex_part_0 | table concur_reindex_part | a + table concur_reindex_part_0_1 | access method tde_heap | n + table concur_reindex_part_0_1 | schema public | n + table concur_reindex_part_0_1 | table concur_reindex_part_0 | a + table concur_reindex_part_0_2 | access method tde_heap | n + table concur_reindex_part_0_2 | schema public | n + table concur_reindex_part_0_2 | table concur_reindex_part_0 | a +(21 rows) + +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_1; +REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_2; +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +REINDEX TABLE CONCURRENTLY concur_reindex_part_0_1; +REINDEX TABLE CONCURRENTLY concur_reindex_part_0_2; +SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_describe_object(refclassid,refobjid,refobjsubid) as objref, + deptype +FROM pg_depend +WHERE classid = 'pg_class'::regclass AND + objid in ('concur_reindex_part'::regclass, + 'concur_reindex_part_0'::regclass, + 'concur_reindex_part_0_1'::regclass, + 'concur_reindex_part_0_2'::regclass, + 'concur_reindex_part_index'::regclass, + 'concur_reindex_part_index_0'::regclass, + 'concur_reindex_part_index_0_1'::regclass, + 'concur_reindex_part_index_0_2'::regclass) + ORDER BY 1, 2; + obj | objref | deptype +------------------------------------------+--------------------------------------------+--------- + column c1 of table concur_reindex_part | table concur_reindex_part | i + column c2 of table concur_reindex_part_0 | table concur_reindex_part_0 | i + index concur_reindex_part_index | column c1 of table concur_reindex_part | a + index concur_reindex_part_index_0 | column c1 of table concur_reindex_part_0 | a + index concur_reindex_part_index_0 | index concur_reindex_part_index | P + index concur_reindex_part_index_0 | table concur_reindex_part_0 | S + index concur_reindex_part_index_0_1 | column c1 of table concur_reindex_part_0_1 | a + index concur_reindex_part_index_0_1 | index concur_reindex_part_index_0 | P + index concur_reindex_part_index_0_1 | table concur_reindex_part_0_1 | S + index concur_reindex_part_index_0_2 | column c1 of table concur_reindex_part_0_2 | a + index concur_reindex_part_index_0_2 | index concur_reindex_part_index_0 | P + index concur_reindex_part_index_0_2 | table concur_reindex_part_0_2 | S + table concur_reindex_part | schema public | n + table concur_reindex_part_0 | schema public | n + table concur_reindex_part_0 | table concur_reindex_part | a + table concur_reindex_part_0_1 | access method tde_heap | n + table concur_reindex_part_0_1 | schema public | n + table concur_reindex_part_0_1 | table concur_reindex_part_0 | a + table concur_reindex_part_0_2 | access method tde_heap | n + table concur_reindex_part_0_2 | schema public | n + table concur_reindex_part_0_2 | table concur_reindex_part_0 | a +(21 rows) + +SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') + ORDER BY relid, level; + relid | parentrelid | level +-------------------------------+-----------------------------+------- + concur_reindex_part_index | | 0 + concur_reindex_part_index_0 | concur_reindex_part_index | 1 + concur_reindex_part_index_10 | concur_reindex_part_index | 1 + concur_reindex_part_index_0_1 | concur_reindex_part_index_0 | 2 + concur_reindex_part_index_0_2 | concur_reindex_part_index_0 | 2 +(5 rows) + +-- REINDEX for partitioned indexes +-- REINDEX TABLE fails for partitioned indexes +-- Top-most parent index +REINDEX TABLE concur_reindex_part_index; -- error +ERROR: "concur_reindex_part_index" is not a table or materialized view +REINDEX TABLE CONCURRENTLY concur_reindex_part_index; -- error +ERROR: "concur_reindex_part_index" is not a table or materialized view +-- Partitioned index with no leaves +REINDEX TABLE concur_reindex_part_index_10; -- error +ERROR: "concur_reindex_part_index_10" is not a table or materialized view +REINDEX TABLE CONCURRENTLY concur_reindex_part_index_10; -- error +ERROR: "concur_reindex_part_index_10" is not a table or materialized view +-- Cannot run in a transaction block +BEGIN; +REINDEX INDEX concur_reindex_part_index; +ERROR: REINDEX INDEX cannot run inside a transaction block +CONTEXT: while reindexing partitioned index "public.concur_reindex_part_index" +ROLLBACK; +-- Helper functions to track changes of relfilenodes in a partition tree. +-- Create a table tracking the relfilenode state. +CREATE OR REPLACE FUNCTION create_relfilenode_part(relname text, indname text) + RETURNS VOID AS + $func$ + BEGIN + EXECUTE format(' + CREATE TABLE %I AS + SELECT oid, relname, relfilenode, relkind, reltoastrelid + FROM pg_class + WHERE oid IN + (SELECT relid FROM pg_partition_tree(''%I''));', + relname, indname); + END + $func$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION compare_relfilenode_part(tabname text) + RETURNS TABLE (relname name, relkind "char", state text) AS + $func$ + BEGIN + RETURN QUERY EXECUTE + format( + 'SELECT b.relname, + b.relkind, + CASE WHEN a.relfilenode = b.relfilenode THEN ''relfilenode is unchanged'' + ELSE ''relfilenode has changed'' END + -- Do not join with OID here as CONCURRENTLY changes it. + FROM %I b JOIN pg_class a ON b.relname = a.relname + ORDER BY 1;', tabname); + END + $func$ LANGUAGE plpgsql; +-- Check that expected relfilenodes are changed, non-concurrent case. +SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index'); + create_relfilenode_part +------------------------- + +(1 row) + +REINDEX INDEX concur_reindex_part_index; +SELECT * FROM compare_relfilenode_part('reindex_index_status'); + relname | relkind | state +-------------------------------+---------+-------------------------- + concur_reindex_part_index | I | relfilenode is unchanged + concur_reindex_part_index_0 | I | relfilenode is unchanged + concur_reindex_part_index_0_1 | i | relfilenode has changed + concur_reindex_part_index_0_2 | i | relfilenode has changed + concur_reindex_part_index_10 | I | relfilenode is unchanged +(5 rows) + +DROP TABLE reindex_index_status; +-- concurrent case. +SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index'); + create_relfilenode_part +------------------------- + +(1 row) + +REINDEX INDEX CONCURRENTLY concur_reindex_part_index; +SELECT * FROM compare_relfilenode_part('reindex_index_status'); + relname | relkind | state +-------------------------------+---------+-------------------------- + concur_reindex_part_index | I | relfilenode is unchanged + concur_reindex_part_index_0 | I | relfilenode is unchanged + concur_reindex_part_index_0_1 | i | relfilenode has changed + concur_reindex_part_index_0_2 | i | relfilenode has changed + concur_reindex_part_index_10 | I | relfilenode is unchanged +(5 rows) + +DROP TABLE reindex_index_status; +-- REINDEX for partitioned tables +-- REINDEX INDEX fails for partitioned tables +-- Top-most parent +REINDEX INDEX concur_reindex_part; -- error +ERROR: "concur_reindex_part" is not an index +REINDEX INDEX CONCURRENTLY concur_reindex_part; -- error +ERROR: "concur_reindex_part" is not an index +-- Partitioned with no leaves +REINDEX INDEX concur_reindex_part_10; -- error +ERROR: "concur_reindex_part_10" is not an index +REINDEX INDEX CONCURRENTLY concur_reindex_part_10; -- error +ERROR: "concur_reindex_part_10" is not an index +-- Cannot run in a transaction block +BEGIN; +REINDEX TABLE concur_reindex_part; +ERROR: REINDEX TABLE cannot run inside a transaction block +CONTEXT: while reindexing partitioned table "public.concur_reindex_part" +ROLLBACK; +-- Check that expected relfilenodes are changed, non-concurrent case. +-- Note that the partition tree changes of the *indexes* need to be checked. +SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index'); + create_relfilenode_part +------------------------- + +(1 row) + +REINDEX TABLE concur_reindex_part; +SELECT * FROM compare_relfilenode_part('reindex_index_status'); + relname | relkind | state +-------------------------------+---------+-------------------------- + concur_reindex_part_index | I | relfilenode is unchanged + concur_reindex_part_index_0 | I | relfilenode is unchanged + concur_reindex_part_index_0_1 | i | relfilenode has changed + concur_reindex_part_index_0_2 | i | relfilenode has changed + concur_reindex_part_index_10 | I | relfilenode is unchanged +(5 rows) + +DROP TABLE reindex_index_status; +-- concurrent case. +SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index'); + create_relfilenode_part +------------------------- + +(1 row) + +REINDEX TABLE CONCURRENTLY concur_reindex_part; +SELECT * FROM compare_relfilenode_part('reindex_index_status'); + relname | relkind | state +-------------------------------+---------+-------------------------- + concur_reindex_part_index | I | relfilenode is unchanged + concur_reindex_part_index_0 | I | relfilenode is unchanged + concur_reindex_part_index_0_1 | i | relfilenode has changed + concur_reindex_part_index_0_2 | i | relfilenode has changed + concur_reindex_part_index_10 | I | relfilenode is unchanged +(5 rows) + +DROP TABLE reindex_index_status; +DROP FUNCTION create_relfilenode_part; +DROP FUNCTION compare_relfilenode_part; +-- Cleanup of partition tree used for REINDEX test. +DROP TABLE concur_reindex_part; +-- Check errors +-- Cannot run inside a transaction block +BEGIN; +REINDEX TABLE CONCURRENTLY concur_reindex_tab; +ERROR: REINDEX CONCURRENTLY cannot run inside a transaction block +COMMIT; +REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation +ERROR: cannot reindex system catalogs concurrently +REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index +ERROR: cannot reindex system catalogs concurrently +-- These are the toast table and index of pg_database. +REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1262; -- no catalog toast table +ERROR: cannot reindex system catalogs concurrently +REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1262_index; -- no catalog toast index +ERROR: cannot reindex system catalogs concurrently +REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM +ERROR: cannot reindex system catalogs concurrently +REINDEX (CONCURRENTLY) SYSTEM postgres; -- ditto +ERROR: cannot reindex system catalogs concurrently +REINDEX (CONCURRENTLY) SYSTEM; -- ditto +ERROR: cannot reindex system catalogs concurrently +-- Warns about catalog relations +REINDEX SCHEMA CONCURRENTLY pg_catalog; +WARNING: cannot reindex system catalogs concurrently, skipping all +-- Not the current database +REINDEX DATABASE not_current_database; +ERROR: can only reindex the currently open database +-- Check the relation status, there should not be invalid indexes +\d concur_reindex_tab + Table "public.concur_reindex_tab" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | not null | + c2 | text | | | +Indexes: + "concur_reindex_ind1" PRIMARY KEY, btree (c1) + "concur_reindex_ind2" btree (c2) + "concur_reindex_ind3" UNIQUE, btree (abs(c1)) + "concur_reindex_ind4" btree (c1, c1, c2) +Referenced by: + TABLE "concur_reindex_tab2" CONSTRAINT "concur_reindex_tab2_c1_fkey" FOREIGN KEY (c1) REFERENCES concur_reindex_tab(c1) + +DROP MATERIALIZED VIEW concur_reindex_matview; +DROP TABLE concur_reindex_tab, concur_reindex_tab2, concur_reindex_tab3; +-- Check handling of invalid indexes +CREATE TABLE concur_reindex_tab4 (c1 int); +INSERT INTO concur_reindex_tab4 VALUES (1), (1), (2); +-- This trick creates an invalid index. +CREATE UNIQUE INDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1); +ERROR: could not create unique index "concur_reindex_ind5" +DETAIL: Key (c1)=(1) is duplicated. +-- Reindexing concurrently this index fails with the same failure. +-- The extra index created is itself invalid, and can be dropped. +REINDEX INDEX CONCURRENTLY concur_reindex_ind5; +ERROR: could not create unique index "concur_reindex_ind5_ccnew" +DETAIL: Key (c1)=(1) is duplicated. +\d concur_reindex_tab4 + Table "public.concur_reindex_tab4" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | +Indexes: + "concur_reindex_ind5" UNIQUE, btree (c1) INVALID + "concur_reindex_ind5_ccnew" UNIQUE, btree (c1) INVALID + +DROP INDEX concur_reindex_ind5_ccnew; +-- This makes the previous failure go away, so the index can become valid. +DELETE FROM concur_reindex_tab4 WHERE c1 = 1; +-- The invalid index is not processed when running REINDEX TABLE. +REINDEX TABLE CONCURRENTLY concur_reindex_tab4; +WARNING: skipping reindex of invalid index "public.concur_reindex_ind5" +HINT: Use DROP INDEX or REINDEX INDEX. +NOTICE: table "concur_reindex_tab4" has no indexes that can be reindexed concurrently +\d concur_reindex_tab4 + Table "public.concur_reindex_tab4" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | +Indexes: + "concur_reindex_ind5" UNIQUE, btree (c1) INVALID + +-- But it is fixed with REINDEX INDEX. +REINDEX INDEX CONCURRENTLY concur_reindex_ind5; +\d concur_reindex_tab4 + Table "public.concur_reindex_tab4" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | +Indexes: + "concur_reindex_ind5" UNIQUE, btree (c1) + +DROP TABLE concur_reindex_tab4; +-- Check handling of indexes with expressions and predicates. The +-- definitions of the rebuilt indexes should match the original +-- definitions. +CREATE TABLE concur_exprs_tab (c1 int , c2 boolean); +INSERT INTO concur_exprs_tab (c1, c2) VALUES (1369652450, FALSE), + (414515746, TRUE), + (897778963, FALSE); +CREATE UNIQUE INDEX concur_exprs_index_expr + ON concur_exprs_tab ((c1::text COLLATE "C")); +CREATE UNIQUE INDEX concur_exprs_index_pred ON concur_exprs_tab (c1) + WHERE (c1::text > 500000000::text COLLATE "C"); +CREATE UNIQUE INDEX concur_exprs_index_pred_2 + ON concur_exprs_tab ((1 / c1)) + WHERE ('-H') >= (c2::TEXT) COLLATE "C"; +ALTER INDEX concur_exprs_index_expr ALTER COLUMN 1 SET STATISTICS 100; +ANALYZE concur_exprs_tab; +SELECT starelid::regclass, count(*) FROM pg_statistic WHERE starelid IN ( + 'concur_exprs_index_expr'::regclass, + 'concur_exprs_index_pred'::regclass, + 'concur_exprs_index_pred_2'::regclass) + GROUP BY starelid ORDER BY starelid::regclass::text; + starelid | count +-------------------------+------- + concur_exprs_index_expr | 1 +(1 row) + +SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass); + pg_get_indexdef +--------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_expr ON public.concur_exprs_tab USING btree (((c1)::text) COLLATE "C") +(1 row) + +SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass); + pg_get_indexdef +---------------------------------------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_pred ON public.concur_exprs_tab USING btree (c1) WHERE ((c1)::text > ((500000000)::text COLLATE "C")) +(1 row) + +SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass); + pg_get_indexdef +-------------------------------------------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_pred_2 ON public.concur_exprs_tab USING btree (((1 / c1))) WHERE ('-H'::text >= ((c2)::text COLLATE "C")) +(1 row) + +REINDEX TABLE CONCURRENTLY concur_exprs_tab; +SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass); + pg_get_indexdef +--------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_expr ON public.concur_exprs_tab USING btree (((c1)::text) COLLATE "C") +(1 row) + +SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass); + pg_get_indexdef +---------------------------------------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_pred ON public.concur_exprs_tab USING btree (c1) WHERE ((c1)::text > ((500000000)::text COLLATE "C")) +(1 row) + +SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass); + pg_get_indexdef +-------------------------------------------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_pred_2 ON public.concur_exprs_tab USING btree (((1 / c1))) WHERE ('-H'::text >= ((c2)::text COLLATE "C")) +(1 row) + +-- ALTER TABLE recreates the indexes, which should keep their collations. +ALTER TABLE concur_exprs_tab ALTER c2 TYPE TEXT; +SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass); + pg_get_indexdef +--------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_expr ON public.concur_exprs_tab USING btree (((c1)::text) COLLATE "C") +(1 row) + +SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass); + pg_get_indexdef +---------------------------------------------------------------------------------------------------------------------------------------------- + CREATE UNIQUE INDEX concur_exprs_index_pred ON public.concur_exprs_tab USING btree (c1) WHERE ((c1)::text > ((500000000)::text COLLATE "C")) +(1 row) + +SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass); + pg_get_indexdef +------------------------------------------------------------------------------------------------------------------------------------------ + CREATE UNIQUE INDEX concur_exprs_index_pred_2 ON public.concur_exprs_tab USING btree (((1 / c1))) WHERE ('-H'::text >= (c2 COLLATE "C")) +(1 row) + +-- Statistics should remain intact. +SELECT starelid::regclass, count(*) FROM pg_statistic WHERE starelid IN ( + 'concur_exprs_index_expr'::regclass, + 'concur_exprs_index_pred'::regclass, + 'concur_exprs_index_pred_2'::regclass) + GROUP BY starelid ORDER BY starelid::regclass::text; + starelid | count +-------------------------+------- + concur_exprs_index_expr | 1 +(1 row) + +-- attstattarget should remain intact +SELECT attrelid::regclass, attnum, attstattarget + FROM pg_attribute WHERE attrelid IN ( + 'concur_exprs_index_expr'::regclass, + 'concur_exprs_index_pred'::regclass, + 'concur_exprs_index_pred_2'::regclass) + ORDER BY attrelid::regclass::text, attnum; + attrelid | attnum | attstattarget +---------------------------+--------+--------------- + concur_exprs_index_expr | 1 | 100 + concur_exprs_index_pred | 1 | + concur_exprs_index_pred_2 | 1 | +(3 rows) + +DROP TABLE concur_exprs_tab; +-- Temporary tables and on-commit actions, where CONCURRENTLY is ignored. +-- ON COMMIT PRESERVE ROWS, the default. +CREATE TEMP TABLE concur_temp_tab_1 (c1 int, c2 text) + ON COMMIT PRESERVE ROWS; +INSERT INTO concur_temp_tab_1 VALUES (1, 'foo'), (2, 'bar'); +CREATE INDEX concur_temp_ind_1 ON concur_temp_tab_1(c2); +REINDEX TABLE CONCURRENTLY concur_temp_tab_1; +REINDEX INDEX CONCURRENTLY concur_temp_ind_1; +-- Still fails in transaction blocks +BEGIN; +REINDEX INDEX CONCURRENTLY concur_temp_ind_1; +ERROR: REINDEX CONCURRENTLY cannot run inside a transaction block +COMMIT; +-- ON COMMIT DELETE ROWS +CREATE TEMP TABLE concur_temp_tab_2 (c1 int, c2 text) + ON COMMIT DELETE ROWS; +CREATE INDEX concur_temp_ind_2 ON concur_temp_tab_2(c2); +REINDEX TABLE CONCURRENTLY concur_temp_tab_2; +REINDEX INDEX CONCURRENTLY concur_temp_ind_2; +-- ON COMMIT DROP +BEGIN; +CREATE TEMP TABLE concur_temp_tab_3 (c1 int, c2 text) + ON COMMIT PRESERVE ROWS; +INSERT INTO concur_temp_tab_3 VALUES (1, 'foo'), (2, 'bar'); +CREATE INDEX concur_temp_ind_3 ON concur_temp_tab_3(c2); +-- Fails when running in a transaction +REINDEX INDEX CONCURRENTLY concur_temp_ind_3; +ERROR: REINDEX CONCURRENTLY cannot run inside a transaction block +COMMIT; +-- REINDEX SCHEMA processes all temporary relations +CREATE TABLE reindex_temp_before AS +SELECT oid, relname, relfilenode, relkind, reltoastrelid + FROM pg_class + WHERE relname IN ('concur_temp_ind_1', 'concur_temp_ind_2'); +SELECT pg_my_temp_schema()::regnamespace as temp_schema_name \gset +REINDEX SCHEMA CONCURRENTLY :temp_schema_name; +SELECT b.relname, + b.relkind, + CASE WHEN a.relfilenode = b.relfilenode THEN 'relfilenode is unchanged' + ELSE 'relfilenode has changed' END + FROM reindex_temp_before b JOIN pg_class a ON b.oid = a.oid + ORDER BY 1; + relname | relkind | case +-------------------+---------+------------------------- + concur_temp_ind_1 | i | relfilenode has changed + concur_temp_ind_2 | i | relfilenode has changed +(2 rows) + +DROP TABLE concur_temp_tab_1, concur_temp_tab_2, reindex_temp_before; +-- No OR-clause groupings should happen, and there should be no clause +-- permutations in the filtering conditions we could see in the EXPLAIN. +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 WHERE unique1 < 1 OR hundred < 2; + QUERY PLAN +-------------------------------------------------- + Bitmap Heap Scan on tenk1 + Recheck Cond: ((unique1 < 1) OR (hundred < 2)) + -> BitmapOr + -> Bitmap Index Scan on tenk1_unique1 + Index Cond: (unique1 < 1) + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred < 2) +(7 rows) + +-- OR clauses in the 'unique1' column are grouped, so clause permutation +-- occurs. W e can see it in the 'Recheck Cond': the second clause involving +-- the 'unique1' column goes just after the first one. +EXPLAIN (COSTS OFF) +SELECT * FROM tenk1 WHERE unique1 < 1 OR unique1 < 3 OR hundred < 2; + QUERY PLAN +--------------------------------------------------------------------- + Bitmap Heap Scan on tenk1 + Recheck Cond: (((unique1 < 1) OR (unique1 < 3)) OR (hundred < 2)) + -> BitmapOr + -> Bitmap Index Scan on tenk1_unique1 + Index Cond: (unique1 < ANY ('{1,3}'::integer[])) + -> Bitmap Index Scan on tenk1_hundred + Index Cond: (hundred < 2) +(7 rows) + +-- Check bitmap scan can consider similar OR arguments separately without +-- grouping them into SAOP. +CREATE TABLE bitmap_split_or (a int NOT NULL, b int NOT NULL, c int NOT NULL); +INSERT INTO bitmap_split_or (SELECT 1, 1, i FROM generate_series(1, 1000) i); +INSERT INTO bitmap_split_or (select i, 2, 2 FROM generate_series(1, 1000) i); +VACUUM ANALYZE bitmap_split_or; +CREATE INDEX t_b_partial_1_idx ON bitmap_split_or (b) WHERE a = 1; +CREATE INDEX t_b_partial_2_idx ON bitmap_split_or (b) WHERE a = 2; +EXPLAIN (COSTS OFF) +SELECT * FROM bitmap_split_or WHERE (a = 1 OR a = 2) AND b = 2; + QUERY PLAN +------------------------------------------------------------------ + Bitmap Heap Scan on bitmap_split_or + Recheck Cond: (((b = 2) AND (a = 1)) OR ((b = 2) AND (a = 2))) + -> BitmapOr + -> Bitmap Index Scan on t_b_partial_1_idx + Index Cond: (b = 2) + -> Bitmap Index Scan on t_b_partial_2_idx + Index Cond: (b = 2) +(7 rows) + +DROP INDEX t_b_partial_1_idx; +DROP INDEX t_b_partial_2_idx; +CREATE INDEX t_a_b_idx ON bitmap_split_or (a, b); +CREATE INDEX t_b_c_idx ON bitmap_split_or (b, c); +CREATE STATISTICS t_a_b_stat (mcv) ON a, b FROM bitmap_split_or; +CREATE STATISTICS t_b_c_stat (mcv) ON b, c FROM bitmap_split_or; +ANALYZE bitmap_split_or; +EXPLAIN (COSTS OFF) +SELECT * FROM bitmap_split_or t1, bitmap_split_or t2 +WHERE t1.a = t2.b OR t1.a = 2; + QUERY PLAN +-------------------------------------------------------- + Nested Loop + -> Seq Scan on bitmap_split_or t2 + -> Index Scan using t_a_b_idx on bitmap_split_or t1 + Index Cond: (a = ANY (ARRAY[t2.b, 2])) +(4 rows) + +EXPLAIN (COSTS OFF) +SELECT * FROM bitmap_split_or WHERE a = 1 AND (b = 1 OR b = 2) AND c = 2; + QUERY PLAN +------------------------------------------------------------------ + Bitmap Heap Scan on bitmap_split_or + Recheck Cond: (((b = 1) AND (c = 2)) OR ((a = 1) AND (b = 2))) + Filter: ((a = 1) AND (c = 2)) + -> BitmapOr + -> Bitmap Index Scan on t_b_c_idx + Index Cond: ((b = 1) AND (c = 2)) + -> Bitmap Index Scan on t_a_b_idx + Index Cond: ((a = 1) AND (b = 2)) +(8 rows) + +DROP TABLE bitmap_split_or; +-- +-- REINDEX SCHEMA +-- +REINDEX SCHEMA schema_to_reindex; -- failure, schema does not exist +ERROR: schema "schema_to_reindex" does not exist +CREATE SCHEMA schema_to_reindex; +SET search_path = 'schema_to_reindex'; +CREATE TABLE table1(col1 SERIAL PRIMARY KEY); +INSERT INTO table1 SELECT generate_series(1,400); +CREATE TABLE table2(col1 SERIAL PRIMARY KEY, col2 TEXT NOT NULL); +INSERT INTO table2 SELECT generate_series(1,400), 'abc'; +CREATE INDEX ON table2(col2); +CREATE MATERIALIZED VIEW matview AS SELECT col1 FROM table2; +CREATE INDEX ON matview(col1); +CREATE VIEW view AS SELECT col2 FROM table2; +CREATE TABLE reindex_before AS +SELECT oid, relname, relfilenode, relkind, reltoastrelid + FROM pg_class + where relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'schema_to_reindex'); +INSERT INTO reindex_before +SELECT oid, 'pg_toast_TABLE', relfilenode, relkind, reltoastrelid +FROM pg_class WHERE oid IN + (SELECT reltoastrelid FROM reindex_before WHERE reltoastrelid > 0); +INSERT INTO reindex_before +SELECT oid, 'pg_toast_TABLE_index', relfilenode, relkind, reltoastrelid +FROM pg_class where oid in + (select indexrelid from pg_index where indrelid in + (select reltoastrelid from reindex_before where reltoastrelid > 0)); +REINDEX SCHEMA schema_to_reindex; +CREATE TABLE reindex_after AS SELECT oid, relname, relfilenode, relkind + FROM pg_class + where relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'schema_to_reindex'); +SELECT b.relname, + b.relkind, + CASE WHEN a.relfilenode = b.relfilenode THEN 'relfilenode is unchanged' + ELSE 'relfilenode has changed' END + FROM reindex_before b JOIN pg_class a ON b.oid = a.oid + ORDER BY 1; + relname | relkind | case +----------------------+---------+-------------------------- + matview | m | relfilenode is unchanged + matview_col1_idx | i | relfilenode has changed + pg_toast_TABLE | t | relfilenode is unchanged + pg_toast_TABLE_index | i | relfilenode has changed + table1 | r | relfilenode is unchanged + table1_col1_seq | S | relfilenode is unchanged + table1_pkey | i | relfilenode has changed + table2 | r | relfilenode is unchanged + table2_col1_seq | S | relfilenode is unchanged + table2_col2_idx | i | relfilenode has changed + table2_pkey | i | relfilenode has changed + view | v | relfilenode is unchanged +(12 rows) + +REINDEX SCHEMA schema_to_reindex; +BEGIN; +REINDEX SCHEMA schema_to_reindex; -- failure, cannot run in a transaction +ERROR: REINDEX SCHEMA cannot run inside a transaction block +END; +-- concurrently +REINDEX SCHEMA CONCURRENTLY schema_to_reindex; +-- Failure for unauthorized user +CREATE ROLE regress_reindexuser NOLOGIN; +SET SESSION ROLE regress_reindexuser; +REINDEX SCHEMA schema_to_reindex; +ERROR: must be owner of schema schema_to_reindex +-- Permission failures with toast tables and indexes (pg_authid here) +RESET ROLE; +GRANT USAGE ON SCHEMA pg_toast TO regress_reindexuser; +SET SESSION ROLE regress_reindexuser; +REINDEX TABLE pg_toast.pg_toast_1262; +ERROR: permission denied for table pg_toast_1262 +REINDEX INDEX pg_toast.pg_toast_1262_index; +ERROR: permission denied for index pg_toast_1262_index +-- Clean up +RESET ROLE; +REVOKE USAGE ON SCHEMA pg_toast FROM regress_reindexuser; +DROP ROLE regress_reindexuser; +DROP SCHEMA schema_to_reindex CASCADE; +NOTICE: drop cascades to 6 other objects +DETAIL: drop cascades to table table1 +drop cascades to table table2 +drop cascades to materialized view matview +drop cascades to view view +drop cascades to table reindex_before +drop cascades to table reindex_after diff --git a/src/test/regress/expected/event_trigger_1.out b/src/test/regress/expected/event_trigger_1.out new file mode 100644 index 0000000000000..9e211e5eb7df6 --- /dev/null +++ b/src/test/regress/expected/event_trigger_1.out @@ -0,0 +1,821 @@ +-- should fail, return type mismatch +create event trigger regress_event_trigger + on ddl_command_start + execute procedure pg_backend_pid(); +ERROR: function pg_backend_pid must return type event_trigger +-- OK +create function test_event_trigger() returns event_trigger as $$ +BEGIN + RAISE NOTICE 'test_event_trigger: % %', tg_event, tg_tag; +END +$$ language plpgsql; +-- should fail, can't call it as a plain function +SELECT test_event_trigger(); +ERROR: trigger functions can only be called as triggers +CONTEXT: compilation of PL/pgSQL function "test_event_trigger" near line 1 +-- should fail, event triggers cannot have declared arguments +create function test_event_trigger_arg(name text) +returns event_trigger as $$ BEGIN RETURN 1; END $$ language plpgsql; +ERROR: event trigger functions cannot have declared arguments +CONTEXT: compilation of PL/pgSQL function "test_event_trigger_arg" near line 1 +-- should fail, SQL functions cannot be event triggers +create function test_event_trigger_sql() returns event_trigger as $$ +SELECT 1 $$ language sql; +ERROR: SQL functions cannot return type event_trigger +-- should fail, no elephant_bootstrap entry point +create event trigger regress_event_trigger on elephant_bootstrap + execute procedure test_event_trigger(); +ERROR: unrecognized event name "elephant_bootstrap" +-- OK +create event trigger regress_event_trigger on ddl_command_start + execute procedure test_event_trigger(); +-- OK +create event trigger regress_event_trigger_end on ddl_command_end + execute function test_event_trigger(); +-- should fail, food is not a valid filter variable +create event trigger regress_event_trigger2 on ddl_command_start + when food in ('sandwich') + execute procedure test_event_trigger(); +ERROR: unrecognized filter variable "food" +-- should fail, sandwich is not a valid command tag +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('sandwich') + execute procedure test_event_trigger(); +ERROR: filter value "sandwich" not recognized for filter variable "tag" +-- should fail, create skunkcabbage is not a valid command tag +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('create table', 'create skunkcabbage') + execute procedure test_event_trigger(); +ERROR: filter value "create skunkcabbage" not recognized for filter variable "tag" +-- should fail, can't have event triggers on event triggers +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('DROP EVENT TRIGGER') + execute procedure test_event_trigger(); +ERROR: event triggers are not supported for DROP EVENT TRIGGER +-- should fail, can't have event triggers on global objects +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('CREATE ROLE') + execute procedure test_event_trigger(); +ERROR: event triggers are not supported for CREATE ROLE +-- should fail, can't have event triggers on global objects +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('CREATE DATABASE') + execute procedure test_event_trigger(); +ERROR: event triggers are not supported for CREATE DATABASE +-- should fail, can't have event triggers on global objects +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('CREATE TABLESPACE') + execute procedure test_event_trigger(); +ERROR: event triggers are not supported for CREATE TABLESPACE +-- should fail, can't have same filter variable twice +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('create table') and tag in ('CREATE FUNCTION') + execute procedure test_event_trigger(); +ERROR: filter variable "tag" specified more than once +-- should fail, can't have arguments +create event trigger regress_event_trigger2 on ddl_command_start + execute procedure test_event_trigger('argument not allowed'); +ERROR: syntax error at or near "'argument not allowed'" +LINE 2: execute procedure test_event_trigger('argument not allowe... + ^ +-- OK +create event trigger regress_event_trigger2 on ddl_command_start + when tag in ('create table', 'CREATE FUNCTION') + execute procedure test_event_trigger(); +-- OK +comment on event trigger regress_event_trigger is 'test comment'; +-- drop as non-superuser should fail +create role regress_evt_user; +set role regress_evt_user; +create event trigger regress_event_trigger_noperms on ddl_command_start + execute procedure test_event_trigger(); +ERROR: permission denied to create event trigger "regress_event_trigger_noperms" +HINT: Must be superuser to create an event trigger. +reset role; +-- test enabling and disabling +alter event trigger regress_event_trigger disable; +-- fires _trigger2 and _trigger_end should fire, but not _trigger +create table event_trigger_fire1 (a int); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +alter event trigger regress_event_trigger enable; +set session_replication_role = replica; +-- fires nothing +create table event_trigger_fire2 (a int); +alter event trigger regress_event_trigger enable replica; +-- fires only _trigger +create table event_trigger_fire3 (a int); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +alter event trigger regress_event_trigger enable always; +-- fires only _trigger +create table event_trigger_fire4 (a int); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +reset session_replication_role; +-- fires all three +create table event_trigger_fire5 (a int); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +-- non-top-level command +create function f1() returns int +language plpgsql +as $$ +begin + create table event_trigger_fire6 (a int); + return 0; +end $$; +NOTICE: test_event_trigger: ddl_command_start CREATE FUNCTION +NOTICE: test_event_trigger: ddl_command_start CREATE FUNCTION +NOTICE: test_event_trigger: ddl_command_end CREATE FUNCTION +select f1(); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE + f1 +---- + 0 +(1 row) + +-- non-top-level command +create procedure p1() +language plpgsql +as $$ +begin + create table event_trigger_fire7 (a int); +end $$; +NOTICE: test_event_trigger: ddl_command_start CREATE PROCEDURE +NOTICE: test_event_trigger: ddl_command_end CREATE PROCEDURE +call p1(); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +-- clean up +alter event trigger regress_event_trigger disable; +drop table event_trigger_fire2, event_trigger_fire3, event_trigger_fire4, event_trigger_fire5, event_trigger_fire6, event_trigger_fire7; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE +drop routine f1(), p1(); +NOTICE: test_event_trigger: ddl_command_end DROP ROUTINE +-- regress_event_trigger_end should fire on these commands +grant all on table event_trigger_fire1 to public; +NOTICE: test_event_trigger: ddl_command_end GRANT +comment on table event_trigger_fire1 is 'here is a comment'; +NOTICE: test_event_trigger: ddl_command_end COMMENT +revoke all on table event_trigger_fire1 from public; +NOTICE: test_event_trigger: ddl_command_end REVOKE +drop table event_trigger_fire1; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE +create foreign data wrapper useless; +NOTICE: test_event_trigger: ddl_command_end CREATE FOREIGN DATA WRAPPER +create server useless_server foreign data wrapper useless; +NOTICE: test_event_trigger: ddl_command_end CREATE SERVER +create user mapping for regress_evt_user server useless_server; +NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING +alter default privileges for role regress_evt_user + revoke delete on tables from regress_evt_user; +NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- alter owner to non-superuser should fail +alter event trigger regress_event_trigger owner to regress_evt_user; +ERROR: permission denied to change owner of event trigger "regress_event_trigger" +HINT: The owner of an event trigger must be a superuser. +-- alter owner to superuser should work +alter role regress_evt_user superuser; +alter event trigger regress_event_trigger owner to regress_evt_user; +-- should fail, name collision +alter event trigger regress_event_trigger rename to regress_event_trigger2; +ERROR: event trigger "regress_event_trigger2" already exists +-- OK +alter event trigger regress_event_trigger rename to regress_event_trigger3; +-- should fail, doesn't exist any more +drop event trigger regress_event_trigger; +ERROR: event trigger "regress_event_trigger" does not exist +-- should fail, regress_evt_user owns some objects +drop role regress_evt_user; +ERROR: role "regress_evt_user" cannot be dropped because some objects depend on it +DETAIL: owner of event trigger regress_event_trigger3 +owner of user mapping for regress_evt_user on server useless_server +owner of default privileges on new relations belonging to role regress_evt_user +-- cleanup before next test +-- these are all OK; the second one should emit a NOTICE +drop event trigger if exists regress_event_trigger2; +drop event trigger if exists regress_event_trigger2; +NOTICE: event trigger "regress_event_trigger2" does not exist, skipping +drop event trigger regress_event_trigger3; +drop event trigger regress_event_trigger_end; +-- test support for dropped objects +CREATE SCHEMA schema_one authorization regress_evt_user; +CREATE SCHEMA schema_two authorization regress_evt_user; +CREATE SCHEMA audit_tbls authorization regress_evt_user; +CREATE TEMP TABLE a_temp_tbl (); +SET SESSION AUTHORIZATION regress_evt_user; +CREATE TABLE schema_one.table_one(a int); +CREATE TABLE schema_one."table two"(a int); +CREATE TABLE schema_one.table_three(a int); +CREATE TABLE audit_tbls.schema_one_table_two(the_value text); +CREATE TABLE schema_two.table_two(a int); +CREATE TABLE schema_two.table_three(a int, b text); +CREATE TABLE audit_tbls.schema_two_table_three(the_value text); +CREATE OR REPLACE FUNCTION schema_two.add(int, int) RETURNS int LANGUAGE plpgsql + CALLED ON NULL INPUT + AS $$ BEGIN RETURN coalesce($1,0) + coalesce($2,0); END; $$; +CREATE AGGREGATE schema_two.newton + (BASETYPE = int, SFUNC = schema_two.add, STYPE = int); +RESET SESSION AUTHORIZATION; +CREATE TABLE undroppable_objs ( + object_type text, + object_identity text +); +INSERT INTO undroppable_objs VALUES +('table', 'schema_one.table_three'), +('table', 'audit_tbls.schema_two_table_three'); +CREATE TABLE dropped_objects ( + object_type text, + schema_name text, + object_name text, + object_identity text, + address_names text[], + address_args text[], + is_temporary bool, + original bool, + normal bool +); +-- This tests errors raised within event triggers; the one in audit_tbls +-- uses 2nd-level recursive invocation via test_evtrig_dropped_objects(). +CREATE OR REPLACE FUNCTION undroppable() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +DECLARE + obj record; +BEGIN + PERFORM 1 FROM pg_tables WHERE tablename = 'undroppable_objs'; + IF NOT FOUND THEN + RAISE NOTICE 'table undroppable_objs not found, skipping'; + RETURN; + END IF; + FOR obj IN + SELECT * FROM pg_event_trigger_dropped_objects() JOIN + undroppable_objs USING (object_type, object_identity) + LOOP + RAISE EXCEPTION 'object % of type % cannot be dropped', + obj.object_identity, obj.object_type; + END LOOP; +END; +$$; +CREATE EVENT TRIGGER undroppable ON sql_drop + EXECUTE PROCEDURE undroppable(); +CREATE OR REPLACE FUNCTION test_evtrig_dropped_objects() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +DECLARE + obj record; +BEGIN + FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects() + LOOP + IF obj.object_type = 'table' THEN + EXECUTE format('DROP TABLE IF EXISTS audit_tbls.%I', + format('%s_%s', obj.schema_name, obj.object_name)); + END IF; + + INSERT INTO dropped_objects + (object_type, schema_name, object_name, + object_identity, address_names, address_args, + is_temporary, original, normal) VALUES + (obj.object_type, obj.schema_name, obj.object_name, + obj.object_identity, obj.address_names, obj.address_args, + obj.is_temporary, obj.original, obj.normal); + END LOOP; +END +$$; +CREATE EVENT TRIGGER regress_event_trigger_drop_objects ON sql_drop + WHEN TAG IN ('drop table', 'drop function', 'drop view', + 'drop owned', 'drop schema', 'alter table') + EXECUTE PROCEDURE test_evtrig_dropped_objects(); +ALTER TABLE schema_one.table_one DROP COLUMN a; +DROP SCHEMA schema_one, schema_two CASCADE; +NOTICE: drop cascades to 7 other objects +DETAIL: drop cascades to table schema_two.table_two +drop cascades to table schema_two.table_three +drop cascades to function schema_two.add(integer,integer) +drop cascades to function schema_two.newton(integer) +drop cascades to table schema_one.table_one +drop cascades to table schema_one."table two" +drop cascades to table schema_one.table_three +NOTICE: table "schema_two_table_two" does not exist, skipping +NOTICE: table "audit_tbls_schema_two_table_three" does not exist, skipping +ERROR: object audit_tbls.schema_two_table_three of type table cannot be dropped +CONTEXT: PL/pgSQL function undroppable() line 14 at RAISE +SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three" +PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE +DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three'; +DROP SCHEMA schema_one, schema_two CASCADE; +NOTICE: drop cascades to 7 other objects +DETAIL: drop cascades to table schema_two.table_two +drop cascades to table schema_two.table_three +drop cascades to function schema_two.add(integer,integer) +drop cascades to function schema_two.newton(integer) +drop cascades to table schema_one.table_one +drop cascades to table schema_one."table two" +drop cascades to table schema_one.table_three +NOTICE: table "schema_two_table_two" does not exist, skipping +NOTICE: table "audit_tbls_schema_two_table_three" does not exist, skipping +NOTICE: table "schema_one_table_one" does not exist, skipping +NOTICE: table "schema_one_table two" does not exist, skipping +NOTICE: table "schema_one_table_three" does not exist, skipping +ERROR: object schema_one.table_three of type table cannot be dropped +CONTEXT: PL/pgSQL function undroppable() line 14 at RAISE +DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three'; +DROP SCHEMA schema_one, schema_two CASCADE; +NOTICE: drop cascades to 7 other objects +DETAIL: drop cascades to table schema_two.table_two +drop cascades to table schema_two.table_three +drop cascades to function schema_two.add(integer,integer) +drop cascades to function schema_two.newton(integer) +drop cascades to table schema_one.table_one +drop cascades to table schema_one."table two" +drop cascades to table schema_one.table_three +NOTICE: table "schema_two_table_two" does not exist, skipping +NOTICE: table "audit_tbls_schema_two_table_three" does not exist, skipping +NOTICE: table "schema_one_table_one" does not exist, skipping +NOTICE: table "schema_one_table two" does not exist, skipping +NOTICE: table "schema_one_table_three" does not exist, skipping +-- exclude TOAST objects because they have unstable names +SELECT * FROM dropped_objects + WHERE schema_name IS NULL OR schema_name <> 'pg_toast'; + object_type | schema_name | object_name | object_identity | address_names | address_args | is_temporary | original | normal +--------------+-------------+-------------------------+-------------------------------------+---------------------------------------+-------------------+--------------+----------+-------- + table column | schema_one | | schema_one.table_one.a | {schema_one,table_one,a} | {} | f | t | f + schema | | schema_two | schema_two | {schema_two} | {} | f | t | f + table | schema_two | table_two | schema_two.table_two | {schema_two,table_two} | {} | f | f | t + type | schema_two | table_two | schema_two.table_two | {schema_two.table_two} | {} | f | f | f + type | schema_two | _table_two | schema_two.table_two[] | {schema_two.table_two[]} | {} | f | f | f + table | audit_tbls | schema_two_table_three | audit_tbls.schema_two_table_three | {audit_tbls,schema_two_table_three} | {} | f | t | f + type | audit_tbls | schema_two_table_three | audit_tbls.schema_two_table_three | {audit_tbls.schema_two_table_three} | {} | f | f | f + type | audit_tbls | _schema_two_table_three | audit_tbls.schema_two_table_three[] | {audit_tbls.schema_two_table_three[]} | {} | f | f | f + table | schema_two | table_three | schema_two.table_three | {schema_two,table_three} | {} | f | f | t + type | schema_two | table_three | schema_two.table_three | {schema_two.table_three} | {} | f | f | f + type | schema_two | _table_three | schema_two.table_three[] | {schema_two.table_three[]} | {} | f | f | f + function | schema_two | | schema_two.add(integer,integer) | {schema_two,add} | {integer,integer} | f | f | t + aggregate | schema_two | | schema_two.newton(integer) | {schema_two,newton} | {integer} | f | f | t + schema | | schema_one | schema_one | {schema_one} | {} | f | t | f + table | schema_one | table_one | schema_one.table_one | {schema_one,table_one} | {} | f | f | t + type | schema_one | table_one | schema_one.table_one | {schema_one.table_one} | {} | f | f | f + type | schema_one | _table_one | schema_one.table_one[] | {schema_one.table_one[]} | {} | f | f | f + table | schema_one | table two | schema_one."table two" | {schema_one,"table two"} | {} | f | f | t + type | schema_one | table two | schema_one."table two" | {"schema_one.\"table two\""} | {} | f | f | f + type | schema_one | _table two | schema_one."table two"[] | {"schema_one.\"table two\"[]"} | {} | f | f | f + table | schema_one | table_three | schema_one.table_three | {schema_one,table_three} | {} | f | f | t + type | schema_one | table_three | schema_one.table_three | {schema_one.table_three} | {} | f | f | f + type | schema_one | _table_three | schema_one.table_three[] | {schema_one.table_three[]} | {} | f | f | f +(23 rows) + +DROP OWNED BY regress_evt_user; +NOTICE: schema "audit_tbls" does not exist, skipping +SELECT * FROM dropped_objects WHERE object_type = 'schema'; + object_type | schema_name | object_name | object_identity | address_names | address_args | is_temporary | original | normal +-------------+-------------+-------------+-----------------+---------------+--------------+--------------+----------+-------- + schema | | schema_two | schema_two | {schema_two} | {} | f | t | f + schema | | schema_one | schema_one | {schema_one} | {} | f | t | f + schema | | audit_tbls | audit_tbls | {audit_tbls} | {} | f | t | f +(3 rows) + +DROP ROLE regress_evt_user; +DROP EVENT TRIGGER regress_event_trigger_drop_objects; +DROP EVENT TRIGGER undroppable; +-- Event triggers on relations. +CREATE OR REPLACE FUNCTION event_trigger_report_dropped() + RETURNS event_trigger + LANGUAGE plpgsql +AS $$ +DECLARE r record; +BEGIN + FOR r IN SELECT * from pg_event_trigger_dropped_objects() + LOOP + IF NOT r.normal AND NOT r.original THEN + CONTINUE; + END IF; + RAISE NOTICE 'NORMAL: orig=% normal=% istemp=% type=% identity=% schema=% name=% addr=% args=%', + r.original, r.normal, r.is_temporary, r.object_type, + r.object_identity, r.schema_name, r.object_name, + r.address_names, r.address_args; + END LOOP; +END; $$; +CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop + EXECUTE PROCEDURE event_trigger_report_dropped(); +CREATE OR REPLACE FUNCTION event_trigger_report_end() + RETURNS event_trigger + LANGUAGE plpgsql +AS $$ +DECLARE r RECORD; +BEGIN + FOR r IN SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + RAISE NOTICE 'END: command_tag=% type=% identity=%', + r.command_tag, r.object_type, r.object_identity; + END LOOP; +END; $$; +CREATE EVENT TRIGGER regress_event_trigger_report_end ON ddl_command_end + EXECUTE PROCEDURE event_trigger_report_end(); +CREATE SCHEMA evttrig + CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two', col_c SERIAL) + CREATE INDEX one_idx ON one (col_b) + CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42) + CREATE TABLE id (col_d int NOT NULL GENERATED ALWAYS AS IDENTITY); +NOTICE: END: command_tag=CREATE SCHEMA type=schema identity=evttrig +NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_a_seq +NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_c_seq +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.one +NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_pkey +NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_a_seq +NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_c_seq +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.two +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two +NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.id_col_d_seq +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.id +NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.id_col_d_seq +NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_idx +-- Partitioned tables with a partitioned index +CREATE TABLE evttrig.parted ( + id int PRIMARY KEY) + PARTITION BY RANGE (id); +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.parted +NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.parted_pkey +CREATE TABLE evttrig.part_1_10 PARTITION OF evttrig.parted (id) + FOR VALUES FROM (1) TO (10); +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_1_10 +CREATE TABLE evttrig.part_10_20 PARTITION OF evttrig.parted (id) + FOR VALUES FROM (10) TO (20) PARTITION BY RANGE (id); +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_10_20 +CREATE TABLE evttrig.part_10_15 PARTITION OF evttrig.part_10_20 (id) + FOR VALUES FROM (10) TO (15); +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_10_15 +CREATE TABLE evttrig.part_15_20 PARTITION OF evttrig.part_10_20 (id) + FOR VALUES FROM (15) TO (20); +NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_15_20 +ALTER TABLE evttrig.two DROP COLUMN col_c; +NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.two.col_c schema=evttrig name= addr={evttrig,two,col_c} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table constraint identity=two_col_c_check on evttrig.two schema=evttrig name= addr={evttrig,two,two_col_c_check} args={} +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two +ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT; +NOTICE: NORMAL: orig=t normal=f istemp=f type=default value identity=for evttrig.one.col_b schema=evttrig name= addr={evttrig,one,col_b} args={} +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one +ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey; +NOTICE: NORMAL: orig=t normal=f istemp=f type=table constraint identity=one_pkey on evttrig.one schema=evttrig name= addr={evttrig,one,one_pkey} args={} +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one +ALTER TABLE evttrig.one DROP COLUMN col_c; +NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.one.col_c schema=evttrig name= addr={evttrig,one,col_c} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_c schema=evttrig name= addr={evttrig,one,col_c} args={} +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one +ALTER TABLE evttrig.id ALTER COLUMN col_d SET DATA TYPE bigint; +NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.id_col_d_seq +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.id +ALTER TABLE evttrig.id ALTER COLUMN col_d DROP IDENTITY, + ALTER COLUMN col_d SET DATA TYPE int; +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.id +DROP INDEX evttrig.one_idx; +NOTICE: NORMAL: orig=t normal=f istemp=f type=index identity=evttrig.one_idx schema=evttrig name=one_idx addr={evttrig,one_idx} args={} +DROP SCHEMA evttrig CASCADE; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table evttrig.one +drop cascades to table evttrig.two +drop cascades to table evttrig.id +drop cascades to table evttrig.parted +NOTICE: NORMAL: orig=t normal=f istemp=f type=schema identity=evttrig schema= name=evttrig addr={evttrig} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.one schema=evttrig name=one addr={evttrig,one} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=sequence identity=evttrig.one_col_a_seq schema=evttrig name=one_col_a_seq addr={evttrig,one_col_a_seq} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_a schema=evttrig name= addr={evttrig,one,col_a} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.two schema=evttrig name=two addr={evttrig,two} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.id schema=evttrig name=id addr={evttrig,id} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.parted schema=evttrig name=parted addr={evttrig,parted} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_1_10 schema=evttrig name=part_1_10 addr={evttrig,part_1_10} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_20 schema=evttrig name=part_10_20 addr={evttrig,part_10_20} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_15 schema=evttrig name=part_10_15 addr={evttrig,part_10_15} args={} +NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_15_20 schema=evttrig name=part_15_20 addr={evttrig,part_15_20} args={} +DROP TABLE a_temp_tbl; +NOTICE: NORMAL: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl schema=pg_temp name=a_temp_tbl addr={pg_temp,a_temp_tbl} args={} +-- check unfiltered results, too +CREATE OR REPLACE FUNCTION event_trigger_report_dropped() + RETURNS event_trigger + LANGUAGE plpgsql +AS $$ +DECLARE r record; +BEGIN + FOR r IN SELECT * from pg_event_trigger_dropped_objects() + LOOP + RAISE NOTICE 'DROP: orig=% normal=% istemp=% type=% identity=% schema=% name=% addr=% args=%', + r.original, r.normal, r.is_temporary, r.object_type, + r.object_identity, r.schema_name, r.object_name, + r.address_names, r.address_args; + END LOOP; +END; $$; +NOTICE: END: command_tag=CREATE FUNCTION type=function identity=public.event_trigger_report_dropped() +CREATE FUNCTION event_trigger_dummy_trigger() + RETURNS trigger + LANGUAGE plpgsql +AS $$ +BEGIN + RETURN new; +END; $$; +NOTICE: END: command_tag=CREATE FUNCTION type=function identity=public.event_trigger_dummy_trigger() +CREATE TABLE evtrg_nontemp_table (f1 int primary key, f2 int default 42); +NOTICE: END: command_tag=CREATE TABLE type=table identity=public.evtrg_nontemp_table +NOTICE: END: command_tag=CREATE INDEX type=index identity=public.evtrg_nontemp_table_pkey +CREATE TRIGGER evtrg_nontemp_trig + BEFORE INSERT ON evtrg_nontemp_table + EXECUTE FUNCTION event_trigger_dummy_trigger(); +NOTICE: END: command_tag=CREATE TRIGGER type=trigger identity=evtrg_nontemp_trig on public.evtrg_nontemp_table +CREATE POLICY evtrg_nontemp_pol ON evtrg_nontemp_table USING (f2 > 0); +NOTICE: END: command_tag=CREATE POLICY type=policy identity=evtrg_nontemp_pol on public.evtrg_nontemp_table +DROP TABLE evtrg_nontemp_table; +NOTICE: DROP: orig=t normal=f istemp=f type=table identity=public.evtrg_nontemp_table schema=public name=evtrg_nontemp_table addr={public,evtrg_nontemp_table} args={} +NOTICE: DROP: orig=f normal=f istemp=f type=type identity=public.evtrg_nontemp_table schema=public name=evtrg_nontemp_table addr={public.evtrg_nontemp_table} args={} +NOTICE: DROP: orig=f normal=f istemp=f type=type identity=public.evtrg_nontemp_table[] schema=public name=_evtrg_nontemp_table addr={public.evtrg_nontemp_table[]} args={} +NOTICE: DROP: orig=f normal=f istemp=f type=default value identity=for public.evtrg_nontemp_table.f2 schema=public name= addr={public,evtrg_nontemp_table,f2} args={} +NOTICE: DROP: orig=f normal=f istemp=f type=table constraint identity=evtrg_nontemp_table_f1_not_null on public.evtrg_nontemp_table schema=public name= addr={public,evtrg_nontemp_table,evtrg_nontemp_table_f1_not_null} args={} +NOTICE: DROP: orig=f normal=f istemp=f type=table constraint identity=evtrg_nontemp_table_pkey on public.evtrg_nontemp_table schema=public name= addr={public,evtrg_nontemp_table,evtrg_nontemp_table_pkey} args={} +NOTICE: DROP: orig=f normal=f istemp=f type=index identity=public.evtrg_nontemp_table_pkey schema=public name=evtrg_nontemp_table_pkey addr={public,evtrg_nontemp_table_pkey} args={} +NOTICE: DROP: orig=f normal=f istemp=f type=trigger identity=evtrg_nontemp_trig on public.evtrg_nontemp_table schema=public name= addr={public,evtrg_nontemp_table,evtrg_nontemp_trig} args={} +NOTICE: DROP: orig=f normal=t istemp=f type=policy identity=evtrg_nontemp_pol on public.evtrg_nontemp_table schema=public name= addr={public,evtrg_nontemp_table,evtrg_nontemp_pol} args={} +CREATE TEMP TABLE a_temp_tbl (f1 int primary key, f2 int default 42); +NOTICE: END: command_tag=CREATE TABLE type=table identity=pg_temp.a_temp_tbl +NOTICE: END: command_tag=CREATE INDEX type=index identity=pg_temp.a_temp_tbl_pkey +CREATE TRIGGER a_temp_trig + BEFORE INSERT ON a_temp_tbl + EXECUTE FUNCTION event_trigger_dummy_trigger(); +NOTICE: END: command_tag=CREATE TRIGGER type=trigger identity=a_temp_trig on pg_temp.a_temp_tbl +CREATE POLICY a_temp_pol ON a_temp_tbl USING (f2 > 0); +NOTICE: END: command_tag=CREATE POLICY type=policy identity=a_temp_pol on pg_temp.a_temp_tbl +DROP TABLE a_temp_tbl; +NOTICE: DROP: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl schema=pg_temp name=a_temp_tbl addr={pg_temp,a_temp_tbl} args={} +NOTICE: DROP: orig=f normal=f istemp=t type=type identity=pg_temp.a_temp_tbl schema=pg_temp name=a_temp_tbl addr={pg_temp.a_temp_tbl} args={} +NOTICE: DROP: orig=f normal=f istemp=t type=type identity=pg_temp.a_temp_tbl[] schema=pg_temp name=_a_temp_tbl addr={pg_temp.a_temp_tbl[]} args={} +NOTICE: DROP: orig=f normal=f istemp=t type=default value identity=for pg_temp.a_temp_tbl.f2 schema=pg_temp name= addr={pg_temp,a_temp_tbl,f2} args={} +NOTICE: DROP: orig=f normal=f istemp=t type=table constraint identity=a_temp_tbl_f1_not_null on pg_temp.a_temp_tbl schema=pg_temp name= addr={pg_temp,a_temp_tbl,a_temp_tbl_f1_not_null} args={} +NOTICE: DROP: orig=f normal=f istemp=t type=table constraint identity=a_temp_tbl_pkey on pg_temp.a_temp_tbl schema=pg_temp name= addr={pg_temp,a_temp_tbl,a_temp_tbl_pkey} args={} +NOTICE: DROP: orig=f normal=f istemp=t type=index identity=pg_temp.a_temp_tbl_pkey schema=pg_temp name=a_temp_tbl_pkey addr={pg_temp,a_temp_tbl_pkey} args={} +NOTICE: DROP: orig=f normal=f istemp=t type=trigger identity=a_temp_trig on pg_temp.a_temp_tbl schema=pg_temp name= addr={pg_temp,a_temp_tbl,a_temp_trig} args={} +NOTICE: DROP: orig=f normal=t istemp=t type=policy identity=a_temp_pol on pg_temp.a_temp_tbl schema=pg_temp name= addr={pg_temp,a_temp_tbl,a_temp_pol} args={} +DROP FUNCTION event_trigger_dummy_trigger(); +NOTICE: DROP: orig=t normal=f istemp=f type=function identity=public.event_trigger_dummy_trigger() schema=public name= addr={public,event_trigger_dummy_trigger} args={} +-- CREATE OPERATOR CLASS without FAMILY clause should report +-- both CREATE OPERATOR FAMILY and CREATE OPERATOR CLASS +CREATE OPERATOR CLASS evttrigopclass FOR TYPE int USING btree AS STORAGE int; +NOTICE: END: command_tag=CREATE OPERATOR FAMILY type=operator family identity=public.evttrigopclass USING btree +NOTICE: END: command_tag=CREATE OPERATOR CLASS type=operator class identity=public.evttrigopclass USING btree +DROP EVENT TRIGGER regress_event_trigger_report_dropped; +DROP EVENT TRIGGER regress_event_trigger_report_end; +-- only allowed from within an event trigger function, should fail +select pg_event_trigger_table_rewrite_oid(); +ERROR: pg_event_trigger_table_rewrite_oid() can only be called in a table_rewrite event trigger function +-- test Table Rewrite Event Trigger +CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN + RAISE EXCEPTION 'rewrites not allowed'; +END; +$$; +create event trigger no_rewrite_allowed on table_rewrite + execute procedure test_evtrig_no_rewrite(); +create table rewriteme (id serial primary key, foo float, bar timestamptz); +insert into rewriteme + select x * 1.001 from generate_series(1, 500) as t(x); +alter table rewriteme alter column foo type numeric; +ERROR: rewrites not allowed +CONTEXT: PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE +alter table rewriteme add column baz int default 0; +-- test with more than one reason to rewrite a single table +CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN + RAISE NOTICE 'Table ''%'' is being rewritten (reason = %)', + pg_event_trigger_table_rewrite_oid()::regclass, + pg_event_trigger_table_rewrite_reason(); +END; +$$; +alter table rewriteme + add column onemore int default 0, + add column another int default -1, + alter column foo type numeric(10,4); +NOTICE: Table 'rewriteme' is being rewritten (reason = 4) +-- matview rewrite when changing access method +CREATE MATERIALIZED VIEW heapmv USING heap AS SELECT 1 AS a; +ALTER MATERIALIZED VIEW heapmv SET ACCESS METHOD heap2; +NOTICE: Table 'heapmv' is being rewritten (reason = 8) +DROP MATERIALIZED VIEW heapmv; +-- shouldn't trigger a table_rewrite event +alter table rewriteme alter column foo type numeric(12,4); +begin; +set timezone to 'UTC'; +alter table rewriteme alter column bar type timestamp; +set timezone to '0'; +alter table rewriteme alter column bar type timestamptz; +set timezone to 'Europe/London'; +alter table rewriteme alter column bar type timestamp; -- does rewrite +NOTICE: Table 'rewriteme' is being rewritten (reason = 4) +rollback; +-- typed tables are rewritten when their type changes. Don't emit table +-- name, because firing order is not stable. +CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN + RAISE NOTICE 'Table is being rewritten (reason = %)', + pg_event_trigger_table_rewrite_reason(); +END; +$$; +create type rewritetype as (a int); +create table rewritemetoo1 of rewritetype; +create table rewritemetoo2 of rewritetype; +alter type rewritetype alter attribute a type text cascade; +NOTICE: Table is being rewritten (reason = 4) +NOTICE: Table is being rewritten (reason = 4) +-- but this doesn't work +create table rewritemetoo3 (a rewritetype); +alter type rewritetype alter attribute a type varchar cascade; +ERROR: cannot alter type "rewritetype" because column "rewritemetoo3.a" uses it +drop table rewriteme; +drop event trigger no_rewrite_allowed; +drop function test_evtrig_no_rewrite(); +-- Tests for REINDEX +CREATE OR REPLACE FUNCTION reindex_start_command() +RETURNS event_trigger AS $$ +BEGIN + RAISE NOTICE 'REINDEX START: % %', tg_event, tg_tag; +END; +$$ LANGUAGE plpgsql; +CREATE EVENT TRIGGER regress_reindex_start ON ddl_command_start + WHEN TAG IN ('REINDEX') + EXECUTE PROCEDURE reindex_start_command(); +CREATE FUNCTION reindex_end_command() +RETURNS event_trigger AS $$ +DECLARE + obj record; +BEGIN + FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + RAISE NOTICE 'REINDEX END: command_tag=% type=% identity=%', + obj.command_tag, obj.object_type, obj.object_identity; + END LOOP; +END; +$$ LANGUAGE plpgsql; +CREATE EVENT TRIGGER regress_reindex_end ON ddl_command_end + WHEN TAG IN ('REINDEX') + EXECUTE PROCEDURE reindex_end_command(); +-- Extra event to force the use of a snapshot. +CREATE FUNCTION reindex_end_command_snap() RETURNS EVENT_TRIGGER + AS $$ BEGIN PERFORM 1; END $$ LANGUAGE plpgsql; +CREATE EVENT TRIGGER regress_reindex_end_snap ON ddl_command_end + EXECUTE FUNCTION reindex_end_command_snap(); +-- With simple relation +CREATE TABLE concur_reindex_tab (c1 int); +CREATE INDEX concur_reindex_ind ON concur_reindex_tab (c1); +-- Both start and end triggers enabled. +REINDEX INDEX concur_reindex_ind; +NOTICE: REINDEX START: ddl_command_start REINDEX +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind +REINDEX TABLE concur_reindex_tab; +NOTICE: REINDEX START: ddl_command_start REINDEX +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind +REINDEX INDEX CONCURRENTLY concur_reindex_ind; +NOTICE: REINDEX START: ddl_command_start REINDEX +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind +REINDEX TABLE CONCURRENTLY concur_reindex_tab; +NOTICE: REINDEX START: ddl_command_start REINDEX +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind +-- with start trigger disabled. +ALTER EVENT TRIGGER regress_reindex_start DISABLE; +REINDEX INDEX concur_reindex_ind; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind +REINDEX INDEX CONCURRENTLY concur_reindex_ind; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind +-- without an index +DROP INDEX concur_reindex_ind; +REINDEX TABLE concur_reindex_tab; +NOTICE: table "concur_reindex_tab" has no indexes to reindex +REINDEX TABLE CONCURRENTLY concur_reindex_tab; +NOTICE: table "concur_reindex_tab" has no indexes that can be reindexed concurrently +-- With a Schema +CREATE SCHEMA concur_reindex_schema; +-- No indexes +REINDEX SCHEMA concur_reindex_schema; +REINDEX SCHEMA CONCURRENTLY concur_reindex_schema; +CREATE TABLE concur_reindex_schema.tab (a int); +CREATE INDEX ind ON concur_reindex_schema.tab (a); +-- One index reported +REINDEX SCHEMA concur_reindex_schema; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=concur_reindex_schema.ind +REINDEX SCHEMA CONCURRENTLY concur_reindex_schema; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=concur_reindex_schema.ind +-- One table on schema but no indexes +DROP INDEX concur_reindex_schema.ind; +REINDEX SCHEMA concur_reindex_schema; +REINDEX SCHEMA CONCURRENTLY concur_reindex_schema; +DROP SCHEMA concur_reindex_schema CASCADE; +NOTICE: drop cascades to table concur_reindex_schema.tab +-- With a partitioned table, and nothing else. +CREATE TABLE concur_reindex_part (id int) PARTITION BY RANGE (id); +REINDEX TABLE concur_reindex_part; +REINDEX TABLE CONCURRENTLY concur_reindex_part; +-- Partition that would be reindexed, still nothing. +CREATE TABLE concur_reindex_child PARTITION OF concur_reindex_part + FOR VALUES FROM (0) TO (10); +REINDEX TABLE concur_reindex_part; +REINDEX TABLE CONCURRENTLY concur_reindex_part; +-- Now add some indexes. +CREATE INDEX concur_reindex_partidx ON concur_reindex_part (id); +REINDEX INDEX concur_reindex_partidx; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx +REINDEX INDEX CONCURRENTLY concur_reindex_partidx; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx +REINDEX TABLE concur_reindex_part; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx +REINDEX TABLE CONCURRENTLY concur_reindex_part; +NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx +DROP TABLE concur_reindex_part; +-- Clean up +DROP EVENT TRIGGER regress_reindex_start; +DROP EVENT TRIGGER regress_reindex_end; +DROP EVENT TRIGGER regress_reindex_end_snap; +DROP FUNCTION reindex_end_command(); +DROP FUNCTION reindex_end_command_snap(); +DROP FUNCTION reindex_start_command(); +DROP TABLE concur_reindex_tab; +-- test Row Security Event Trigger +RESET SESSION AUTHORIZATION; +CREATE TABLE event_trigger_test (a integer, b text); +CREATE OR REPLACE FUNCTION start_command() +RETURNS event_trigger AS $$ +BEGIN +RAISE NOTICE '% - ddl_command_start', tg_tag; +END; +$$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION end_command() +RETURNS event_trigger AS $$ +BEGIN +RAISE NOTICE '% - ddl_command_end', tg_tag; +END; +$$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION drop_sql_command() +RETURNS event_trigger AS $$ +BEGIN +RAISE NOTICE '% - sql_drop', tg_tag; +END; +$$ LANGUAGE plpgsql; +CREATE EVENT TRIGGER start_rls_command ON ddl_command_start + WHEN TAG IN ('CREATE POLICY', 'ALTER POLICY', 'DROP POLICY') EXECUTE PROCEDURE start_command(); +CREATE EVENT TRIGGER end_rls_command ON ddl_command_end + WHEN TAG IN ('CREATE POLICY', 'ALTER POLICY', 'DROP POLICY') EXECUTE PROCEDURE end_command(); +CREATE EVENT TRIGGER sql_drop_command ON sql_drop + WHEN TAG IN ('DROP POLICY') EXECUTE PROCEDURE drop_sql_command(); +CREATE POLICY p1 ON event_trigger_test USING (FALSE); +NOTICE: CREATE POLICY - ddl_command_start +NOTICE: CREATE POLICY - ddl_command_end +ALTER POLICY p1 ON event_trigger_test USING (TRUE); +NOTICE: ALTER POLICY - ddl_command_start +NOTICE: ALTER POLICY - ddl_command_end +ALTER POLICY p1 ON event_trigger_test RENAME TO p2; +NOTICE: ALTER POLICY - ddl_command_start +NOTICE: ALTER POLICY - ddl_command_end +DROP POLICY p2 ON event_trigger_test; +NOTICE: DROP POLICY - ddl_command_start +NOTICE: DROP POLICY - sql_drop +NOTICE: DROP POLICY - ddl_command_end +-- Check the object addresses of all the event triggers. +SELECT + e.evtname, + pg_describe_object('pg_event_trigger'::regclass, e.oid, 0) as descr, + b.type, b.object_names, b.object_args, + pg_identify_object(a.classid, a.objid, a.objsubid) as ident + FROM pg_event_trigger as e, + LATERAL pg_identify_object_as_address('pg_event_trigger'::regclass, e.oid, 0) as b, + LATERAL pg_get_object_address(b.type, b.object_names, b.object_args) as a + ORDER BY e.evtname; + evtname | descr | type | object_names | object_args | ident +-------------------+---------------------------------+---------------+---------------------+-------------+-------------------------------------------------------- + end_rls_command | event trigger end_rls_command | event trigger | {end_rls_command} | {} | ("event trigger",,end_rls_command,end_rls_command) + pg_tde_ddl_end | event trigger pg_tde_ddl_end | event trigger | {pg_tde_ddl_end} | {} | ("event trigger",,pg_tde_ddl_end,pg_tde_ddl_end) + pg_tde_ddl_start | event trigger pg_tde_ddl_start | event trigger | {pg_tde_ddl_start} | {} | ("event trigger",,pg_tde_ddl_start,pg_tde_ddl_start) + sql_drop_command | event trigger sql_drop_command | event trigger | {sql_drop_command} | {} | ("event trigger",,sql_drop_command,sql_drop_command) + start_rls_command | event trigger start_rls_command | event trigger | {start_rls_command} | {} | ("event trigger",,start_rls_command,start_rls_command) +(5 rows) + +DROP EVENT TRIGGER start_rls_command; +DROP EVENT TRIGGER end_rls_command; +DROP EVENT TRIGGER sql_drop_command; +-- Check the GUC for disabling event triggers +CREATE FUNCTION test_event_trigger_guc() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +DECLARE + obj record; +BEGIN + FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects() + LOOP + RAISE NOTICE '% dropped %', tg_tag, obj.object_type; + END LOOP; +END; +$$; +CREATE EVENT TRIGGER test_event_trigger_guc + ON sql_drop + WHEN TAG IN ('DROP POLICY') EXECUTE FUNCTION test_event_trigger_guc(); +SET event_triggers = 'on'; +CREATE POLICY pguc ON event_trigger_test USING (FALSE); +DROP POLICY pguc ON event_trigger_test; +NOTICE: DROP POLICY dropped policy +CREATE POLICY pguc ON event_trigger_test USING (FALSE); +SET event_triggers = 'off'; +DROP POLICY pguc ON event_trigger_test; diff --git a/src/test/regress/expected/psql_1.out b/src/test/regress/expected/psql_1.out new file mode 100644 index 0000000000000..667d23abe0c93 --- /dev/null +++ b/src/test/regress/expected/psql_1.out @@ -0,0 +1,6939 @@ +-- +-- Tests for psql features that aren't closely connected to any +-- specific server features +-- +-- \set +-- fail: invalid name +\set invalid/name foo +invalid variable name: "invalid/name" +-- fail: invalid value for special variable +\set AUTOCOMMIT foo +unrecognized value "foo" for "AUTOCOMMIT": Boolean expected +\set FETCH_COUNT foo +invalid value "foo" for "FETCH_COUNT": integer expected +-- check handling of built-in boolean variable +\echo :ON_ERROR_ROLLBACK +off +\set ON_ERROR_ROLLBACK +\echo :ON_ERROR_ROLLBACK +on +\set ON_ERROR_ROLLBACK foo +unrecognized value "foo" for "ON_ERROR_ROLLBACK" +Available values are: on, off, interactive. +\echo :ON_ERROR_ROLLBACK +on +\set ON_ERROR_ROLLBACK on +\echo :ON_ERROR_ROLLBACK +on +\unset ON_ERROR_ROLLBACK +\echo :ON_ERROR_ROLLBACK +off +-- \g and \gx +SELECT 1 as one, 2 as two \g + one | two +-----+----- + 1 | 2 +(1 row) + +\gx +-[ RECORD 1 ] +one | 1 +two | 2 + +SELECT 3 as three, 4 as four \gx +-[ RECORD 1 ] +three | 3 +four | 4 + +\g + three | four +-------+------ + 3 | 4 +(1 row) + +-- \gx should work in FETCH_COUNT mode too +\set FETCH_COUNT 1 +SELECT 1 as one, 2 as two \g + one | two +-----+----- + 1 | 2 +(1 row) + +\gx +-[ RECORD 1 ] +one | 1 +two | 2 + +SELECT 3 as three, 4 as four \gx +-[ RECORD 1 ] +three | 3 +four | 4 + +\g + three | four +-------+------ + 3 | 4 +(1 row) + +\unset FETCH_COUNT +-- \g/\gx with pset options +SELECT 1 as one, 2 as two \g (format=csv csv_fieldsep='\t') +one two +1 2 +\g + one | two +-----+----- + 1 | 2 +(1 row) + +SELECT 1 as one, 2 as two \gx (title='foo bar') +foo bar +-[ RECORD 1 ] +one | 1 +two | 2 + +\g + one | two +-----+----- + 1 | 2 +(1 row) + +-- \parse (extended query protocol) +\parse +\parse: missing required argument +SELECT 1 \parse '' +SELECT 2 \parse stmt1 +SELECT $1 \parse stmt2 +SELECT $1, $2 \parse stmt3 +-- \bind_named (extended query protocol) +\bind_named +\bind_named: missing required argument +\bind_named '' \g + ?column? +---------- + 1 +(1 row) + +\bind_named stmt1 \g + ?column? +---------- + 2 +(1 row) + +\bind_named stmt2 'foo' \g + ?column? +---------- + foo +(1 row) + +\bind_named stmt3 'foo' 'bar' \g + ?column? | ?column? +----------+---------- + foo | bar +(1 row) + +-- Repeated calls. The second call generates an error, cleaning up the +-- statement name set by the first call. +\bind_named stmt4 +\bind_named +\bind_named: missing required argument +\g +ERROR: there is no parameter $1 +LINE 1: SELECT $1, $2 + ^ +-- Last \bind_named wins +\bind_named stmt2 'foo' \bind_named stmt3 'foo2' 'bar2' \g + ?column? | ?column? +----------+---------- + foo2 | bar2 +(1 row) + +-- Multiple \g calls mean multiple executions +\bind_named stmt2 'foo3' \g \bind_named stmt3 'foo4' 'bar4' \g + ?column? +---------- + foo3 +(1 row) + + ?column? | ?column? +----------+---------- + foo4 | bar4 +(1 row) + +-- \close_prepared (extended query protocol) +\close_prepared +\close_prepared: missing required argument +\close_prepared '' +\close_prepared stmt2 +\close_prepared stmt2 +SELECT name, statement FROM pg_prepared_statements ORDER BY name; + name | statement +-------+---------------- + stmt1 | SELECT 2 + stmt3 | SELECT $1, $2 +(2 rows) + +-- \bind (extended query protocol) +SELECT 1 \bind \g + ?column? +---------- + 1 +(1 row) + +SELECT $1 \bind 'foo' \g + ?column? +---------- + foo +(1 row) + +SELECT $1, $2 \bind 'foo' 'bar' \g + ?column? | ?column? +----------+---------- + foo | bar +(1 row) + +-- last \bind wins +select $1::int as col \bind 'foo' \bind 2 \g + col +----- + 2 +(1 row) + +-- Multiple \g calls mean multiple executions +select $1::int as col \bind 1 \g \bind 2 \g + col +----- + 1 +(1 row) + + col +----- + 2 +(1 row) + +-- errors +-- parse error +SELECT foo \bind \g +ERROR: column "foo" does not exist +LINE 1: SELECT foo + ^ +-- tcop error +SELECT 1 \; SELECT 2 \bind \g +ERROR: cannot insert multiple commands into a prepared statement +-- bind error +SELECT $1, $2 \bind 'foo' \g +ERROR: bind message supplies 1 parameters, but prepared statement "" requires 2 +-- bind_named error +\bind_named stmt2 'baz' \g +ERROR: prepared statement "stmt2" does not exist +\bind_named stmt3 'baz' \g +ERROR: bind message supplies 1 parameters, but prepared statement "stmt3" requires 2 +-- \gset +select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_ +\echo :pref01_test01 :pref01_test02 :pref01_test03 +10 20 Hello +-- should fail: bad variable name +select 10 as "bad name" +\gset +invalid variable name: "bad name" +select 97 as "EOF", 'ok' as _foo \gset IGNORE +attempt to \gset into specially treated variable "IGNOREEOF" ignored +\echo :IGNORE_foo :IGNOREEOF +ok 0 +-- multiple backslash commands in one line +select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x +1 +select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y +3 +4 +select 5 as x, 6 as y \gset pref01_ \\ \g \echo :pref01_x :pref01_y + x | y +---+--- + 5 | 6 +(1 row) + +5 6 +select 7 as x, 8 as y \g \gset pref01_ \echo :pref01_x :pref01_y + x | y +---+--- + 7 | 8 +(1 row) + +7 8 +-- NULL should unset the variable +\set var2 xyz +select 1 as var1, NULL as var2, 3 as var3 \gset +\echo :var1 :var2 :var3 +1 :var2 3 +-- \gset requires just one tuple +select 10 as test01, 20 as test02 from generate_series(1,3) \gset +more than one row returned for \gset +select 10 as test01, 20 as test02 from generate_series(1,0) \gset +no rows returned for \gset +-- \gset returns no tuples +select a from generate_series(1, 10) as a where a = 11 \gset +no rows returned for \gset +\echo :ROW_COUNT +0 +-- \gset should work in FETCH_COUNT mode too +\set FETCH_COUNT 1 +select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x +1 +select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y +3 +4 +select 10 as test01, 20 as test02 from generate_series(1,3) \gset +more than one row returned for \gset +select 10 as test01, 20 as test02 from generate_series(1,0) \gset +no rows returned for \gset +\unset FETCH_COUNT +-- \gdesc +SELECT + NULL AS zero, + 1 AS one, + 2.0 AS two, + 'three' AS three, + $1 AS four, + sin($2) as five, + 'foo'::varchar(4) as six, + CURRENT_DATE AS now +\gdesc + Column | Type +--------+---------------------- + zero | text + one | integer + two | numeric + three | text + four | text + five | double precision + six | character varying(4) + now | date +(8 rows) + +-- should work with tuple-returning utilities, such as EXECUTE +PREPARE test AS SELECT 1 AS first, 2 AS second; +EXECUTE test \gdesc + Column | Type +--------+--------- + first | integer + second | integer +(2 rows) + +EXPLAIN EXECUTE test \gdesc + Column | Type +------------+------ + QUERY PLAN | text +(1 row) + +-- should fail cleanly - syntax error +SELECT 1 + \gdesc +ERROR: syntax error at end of input +LINE 1: SELECT 1 + + ^ +-- check behavior with empty results +SELECT \gdesc +The command has no result, or the result has no columns. +CREATE TABLE bububu(a int) \gdesc +The command has no result, or the result has no columns. +-- subject command should not have executed +TABLE bububu; -- fail +ERROR: relation "bububu" does not exist +LINE 1: TABLE bububu; + ^ +-- query buffer should remain unchanged +SELECT 1 AS x, 'Hello', 2 AS y, true AS "dirty\name" +\gdesc + Column | Type +------------+--------- + x | integer + ?column? | text + y | integer + dirty\name | boolean +(4 rows) + +\g + x | ?column? | y | dirty\name +---+----------+---+------------ + 1 | Hello | 2 | t +(1 row) + +-- all on one line +SELECT 3 AS x, 'Hello', 4 AS y, true AS "dirty\name" \gdesc \g + Column | Type +------------+--------- + x | integer + ?column? | text + y | integer + dirty\name | boolean +(4 rows) + + x | ?column? | y | dirty\name +---+----------+---+------------ + 3 | Hello | 4 | t +(1 row) + +-- test for server bug #17983 with empty statement in aborted transaction +set search_path = default; +begin; +bogus; +ERROR: syntax error at or near "bogus" +LINE 1: bogus; + ^ +; +\gdesc +The command has no result, or the result has no columns. +rollback; +-- \gexec +create temporary table gexec_test(a int, b text, c date, d float); +select format('create index on gexec_test(%I)', attname) +from pg_attribute +where attrelid = 'gexec_test'::regclass and attnum > 0 +order by attnum +\gexec +create index on gexec_test(a) +create index on gexec_test(b) +create index on gexec_test(c) +create index on gexec_test(d) +-- \gexec should work in FETCH_COUNT mode too +-- (though the fetch limit applies to the executed queries not the meta query) +\set FETCH_COUNT 1 +select 'select 1 as ones', 'select x.y, x.y*2 as double from generate_series(1,4) as x(y)' +union all +select 'drop table gexec_test', NULL +union all +select 'drop table gexec_test', 'select ''2000-01-01''::date as party_over' +\gexec +select 1 as ones + ones +------ + 1 +(1 row) + +select x.y, x.y*2 as double from generate_series(1,4) as x(y) + y | double +---+-------- + 1 | 2 + 2 | 4 + 3 | 6 + 4 | 8 +(4 rows) + +drop table gexec_test +drop table gexec_test +ERROR: table "gexec_test" does not exist +select '2000-01-01'::date as party_over + party_over +------------ + 01-01-2000 +(1 row) + +\unset FETCH_COUNT +-- \setenv, \getenv +-- ensure MYVAR isn't set +\setenv MYVAR +-- in which case, reading it doesn't change the target +\getenv res MYVAR +\echo :res +:res +-- now set it +\setenv MYVAR 'environment value' +\getenv res MYVAR +\echo :res +environment value +-- show all pset options +\pset +border 1 +columns 0 +csv_fieldsep ',' +expanded off +fieldsep '|' +fieldsep_zero off +footer on +format aligned +linestyle ascii +null '' +numericlocale off +pager 1 +pager_min_lines 0 +recordsep '\n' +recordsep_zero off +tableattr +title +tuples_only off +unicode_border_linestyle single +unicode_column_linestyle single +unicode_header_linestyle single +xheader_width full +-- test multi-line headers, wrapping, and newline indicators +-- in aligned, unaligned, and wrapped formats +prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab + +c", array_to_string(array_agg(repeat('y',20-2*n)),E'\n') as "a +bc" from generate_series(1,10) as n(n) group by n>1 order by n>1; +\pset linestyle ascii +\pset expanded off +\pset columns 40 +\pset border 0 +\pset format unaligned +execute q; +ab + +c|a +bc +xx|yyyyyyyyyyyyyyyyyy +xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +(2 rows) +\pset format aligned +execute q; + ab + a + + + bc + c +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx +yyyyyyyyyyyyyyyy + +xxxxxx +yyyyyyyyyyyyyy + +xxxxxxxx +yyyyyyyyyyyy + +xxxxxxxxxx +yyyyyyyyyy + +xxxxxxxxxxxx +yyyyyyyy + +xxxxxxxxxxxxxx +yyyyyy + +xxxxxxxxxxxxxxxx +yyyy + +xxxxxxxxxxxxxxxxxx +yy + +xxxxxxxxxxxxxxxxxxxx +(2 rows) + +\pset format wrapped +execute q; + ab + a + + + bc + c +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx +yyyyyyyyyyyyyyyy + +xxxxxx +yyyyyyyyyyyyyy + +xxxxxxxx +yyyyyyyyyyyy + +xxxxxxxxxx +yyyyyyyyyy + +xxxxxxxxxxxx +yyyyyyyy + +xxxxxxxxxxxxxx +yyyyyy + +xxxxxxxxxxxxxxxx +yyyy + +xxxxxxxxxxxxxxxxxx +yy + +xxxxxxxxxxxxxxxxxxxx +(2 rows) + +\pset border 1 +\pset format unaligned +execute q; +ab + +c|a +bc +xx|yyyyyyyyyyyyyyyyyy +xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +(2 rows) +\pset format aligned +execute q; + ab +| a + + +| bc + c | +----------------------+-------------------- + xx | yyyyyyyyyyyyyyyyyy + xxxx +| yyyyyyyyyyyyyyyy + + xxxxxx +| yyyyyyyyyyyyyy + + xxxxxxxx +| yyyyyyyyyyyy + + xxxxxxxxxx +| yyyyyyyyyy + + xxxxxxxxxxxx +| yyyyyyyy + + xxxxxxxxxxxxxx +| yyyyyy + + xxxxxxxxxxxxxxxx +| yyyy + + xxxxxxxxxxxxxxxxxx +| yy + + xxxxxxxxxxxxxxxxxxxx | +(2 rows) + +\pset format wrapped +execute q; + ab +| a + + +| bc + c | +-------------------+-------------------- + xx | yyyyyyyyyyyyyyyyyy + xxxx +| yyyyyyyyyyyyyyyy + + xxxxxx +| yyyyyyyyyyyyyy + + xxxxxxxx +| yyyyyyyyyyyy + + xxxxxxxxxx +| yyyyyyyyyy + + xxxxxxxxxxxx +| yyyyyyyy + + xxxxxxxxxxxxxx +| yyyyyy + + xxxxxxxxxxxxxxxx +| yyyy + + xxxxxxxxxxxxxxxxx.| yy + +.x +| + xxxxxxxxxxxxxxxxx.| +.xxx | +(2 rows) + +\pset border 2 +\pset format unaligned +execute q; +ab + +c|a +bc +xx|yyyyyyyyyyyyyyyyyy +xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +(2 rows) +\pset format aligned +execute q; ++----------------------+--------------------+ +| ab +| a +| +| +| bc | +| c | | ++----------------------+--------------------+ +| xx | yyyyyyyyyyyyyyyyyy | +| xxxx +| yyyyyyyyyyyyyyyy +| +| xxxxxx +| yyyyyyyyyyyyyy +| +| xxxxxxxx +| yyyyyyyyyyyy +| +| xxxxxxxxxx +| yyyyyyyyyy +| +| xxxxxxxxxxxx +| yyyyyyyy +| +| xxxxxxxxxxxxxx +| yyyyyy +| +| xxxxxxxxxxxxxxxx +| yyyy +| +| xxxxxxxxxxxxxxxxxx +| yy +| +| xxxxxxxxxxxxxxxxxxxx | | ++----------------------+--------------------+ +(2 rows) + +\pset format wrapped +execute q; ++-----------------+--------------------+ +| ab +| a +| +| +| bc | +| c | | ++-----------------+--------------------+ +| xx | yyyyyyyyyyyyyyyyyy | +| xxxx +| yyyyyyyyyyyyyyyy +| +| xxxxxx +| yyyyyyyyyyyyyy +| +| xxxxxxxx +| yyyyyyyyyyyy +| +| xxxxxxxxxx +| yyyyyyyyyy +| +| xxxxxxxxxxxx +| yyyyyyyy +| +| xxxxxxxxxxxxxx +| yyyyyy +| +| xxxxxxxxxxxxxxx.| yyyy +| +|.x +| yy +| +| xxxxxxxxxxxxxxx.| | +|.xxx +| | +| xxxxxxxxxxxxxxx.| | +|.xxxxx | | ++-----------------+--------------------+ +(2 rows) + +\pset expanded on +\pset columns 20 +\pset border 0 +\pset format unaligned +execute q; +ab + +c|xx +a +bc|yyyyyyyyyyyyyyyyyy + +ab + +c|xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx +a +bc|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +\pset format aligned +execute q; +* Record 1 +ab+ xx + + +c +a + yyyyyyyyyyyyyyyyyy +bc +* Record 2 +ab+ xxxx + + + xxxxxx + +c xxxxxxxx + + xxxxxxxxxx + + xxxxxxxxxxxx + + xxxxxxxxxxxxxx + + xxxxxxxxxxxxxxxx + + xxxxxxxxxxxxxxxxxx + + xxxxxxxxxxxxxxxxxxxx +a + yyyyyyyyyyyyyyyy + +bc yyyyyyyyyyyyyy + + yyyyyyyyyyyy + + yyyyyyyyyy + + yyyyyyyy + + yyyyyy + + yyyy + + yy + + + +\pset format wrapped +execute q; +* Record 1 +ab+ xx + + +c +a + yyyyyyyyyyyyyyy. +bc .yyy +* Record 2 +ab+ xxxx + + + xxxxxx + +c xxxxxxxx + + xxxxxxxxxx + + xxxxxxxxxxxx + + xxxxxxxxxxxxxx + + xxxxxxxxxxxxxxx. + .x + + xxxxxxxxxxxxxxx. + .xxx + + xxxxxxxxxxxxxxx. + .xxxxx +a + yyyyyyyyyyyyyyy. +bc .y + + yyyyyyyyyyyyyy + + yyyyyyyyyyyy + + yyyyyyyyyy + + yyyyyyyy + + yyyyyy + + yyyy + + yy + + + +\pset border 1 +\pset format unaligned +execute q; +ab + +c|xx +a +bc|yyyyyyyyyyyyyyyyyy + +ab + +c|xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx +a +bc|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +\pset format aligned +execute q; +-[ RECORD 1 ]------------ +ab+| xx + +| +c | +a +| yyyyyyyyyyyyyyyyyy +bc | +-[ RECORD 2 ]------------ +ab+| xxxx + + +| xxxxxx + +c | xxxxxxxx + + | xxxxxxxxxx + + | xxxxxxxxxxxx + + | xxxxxxxxxxxxxx + + | xxxxxxxxxxxxxxxx + + | xxxxxxxxxxxxxxxxxx + + | xxxxxxxxxxxxxxxxxxxx +a +| yyyyyyyyyyyyyyyy + +bc | yyyyyyyyyyyyyy + + | yyyyyyyyyyyy + + | yyyyyyyyyy + + | yyyyyyyy + + | yyyyyy + + | yyyy + + | yy + + | + +\pset format wrapped +execute q; +-[ RECORD 1 ]------ +ab+| xx + +| +c | +a +| yyyyyyyyyyyyyy. +bc |.yyyy +-[ RECORD 2 ]------ +ab+| xxxx + + +| xxxxxx + +c | xxxxxxxx + + | xxxxxxxxxx + + | xxxxxxxxxxxx + + | xxxxxxxxxxxxxx+ + | xxxxxxxxxxxxxx. + |.xx + + | xxxxxxxxxxxxxx. + |.xxxx + + | xxxxxxxxxxxxxx. + |.xxxxxx +a +| yyyyyyyyyyyyyy. +bc |.yy + + | yyyyyyyyyyyyyy+ + | yyyyyyyyyyyy + + | yyyyyyyyyy + + | yyyyyyyy + + | yyyyyy + + | yyyy + + | yy + + | + +\pset border 2 +\pset format unaligned +execute q; +ab + +c|xx +a +bc|yyyyyyyyyyyyyyyyyy + +ab + +c|xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx +a +bc|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +\pset format aligned +execute q; ++-[ RECORD 1 ]--------------+ +| ab+| xx | +| +| | +| c | | +| a +| yyyyyyyyyyyyyyyyyy | +| bc | | ++-[ RECORD 2 ]--------------+ +| ab+| xxxx +| +| +| xxxxxx +| +| c | xxxxxxxx +| +| | xxxxxxxxxx +| +| | xxxxxxxxxxxx +| +| | xxxxxxxxxxxxxx +| +| | xxxxxxxxxxxxxxxx +| +| | xxxxxxxxxxxxxxxxxx +| +| | xxxxxxxxxxxxxxxxxxxx | +| a +| yyyyyyyyyyyyyyyy +| +| bc | yyyyyyyyyyyyyy +| +| | yyyyyyyyyyyy +| +| | yyyyyyyyyy +| +| | yyyyyyyy +| +| | yyyyyy +| +| | yyyy +| +| | yy +| +| | | ++----+----------------------+ + +\pset format wrapped +execute q; ++-[ RECORD 1 ]-----+ +| ab+| xx | +| +| | +| c | | +| a +| yyyyyyyyyyy.| +| bc |.yyyyyyy | ++-[ RECORD 2 ]-----+ +| ab+| xxxx +| +| +| xxxxxx +| +| c | xxxxxxxx +| +| | xxxxxxxxxx +| +| | xxxxxxxxxxx.| +| |.x +| +| | xxxxxxxxxxx.| +| |.xxx +| +| | xxxxxxxxxxx.| +| |.xxxxx +| +| | xxxxxxxxxxx.| +| |.xxxxxxx +| +| | xxxxxxxxxxx.| +| |.xxxxxxxxx | +| a +| yyyyyyyyyyy.| +| bc |.yyyyy +| +| | yyyyyyyyyyy.| +| |.yyy +| +| | yyyyyyyyyyy.| +| |.y +| +| | yyyyyyyyyy +| +| | yyyyyyyy +| +| | yyyyyy +| +| | yyyy +| +| | yy +| +| | | ++----+-------------+ + +\pset linestyle old-ascii +\pset expanded off +\pset columns 40 +\pset border 0 +\pset format unaligned +execute q; +ab + +c|a +bc +xx|yyyyyyyyyyyyyyyyyy +xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +(2 rows) +\pset format aligned +execute q; + ab a + + bc + c + +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx yyyyyyyyyyyyyyyy +xxxxxx yyyyyyyyyyyyyy +xxxxxxxx yyyyyyyyyyyy +xxxxxxxxxx yyyyyyyyyy +xxxxxxxxxxxx yyyyyyyy +xxxxxxxxxxxxxx yyyyyy +xxxxxxxxxxxxxxxx yyyy +xxxxxxxxxxxxxxxxxx yy +xxxxxxxxxxxxxxxxxxxx +(2 rows) + +\pset format wrapped +execute q; + ab a + + bc + c + +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx yyyyyyyyyyyyyyyy +xxxxxx yyyyyyyyyyyyyy +xxxxxxxx yyyyyyyyyyyy +xxxxxxxxxx yyyyyyyyyy +xxxxxxxxxxxx yyyyyyyy +xxxxxxxxxxxxxx yyyyyy +xxxxxxxxxxxxxxxx yyyy +xxxxxxxxxxxxxxxxxx yy +xxxxxxxxxxxxxxxxxxxx +(2 rows) + +\pset border 1 +\pset format unaligned +execute q; +ab + +c|a +bc +xx|yyyyyyyyyyyyyyyyyy +xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +(2 rows) +\pset format aligned +execute q; + ab | a ++ |+ bc ++ c |+ +----------------------+-------------------- + xx | yyyyyyyyyyyyyyyyyy + xxxx | yyyyyyyyyyyyyyyy + xxxxxx : yyyyyyyyyyyyyy + xxxxxxxx : yyyyyyyyyyyy + xxxxxxxxxx : yyyyyyyyyy + xxxxxxxxxxxx : yyyyyyyy + xxxxxxxxxxxxxx : yyyyyy + xxxxxxxxxxxxxxxx : yyyy + xxxxxxxxxxxxxxxxxx : yy + xxxxxxxxxxxxxxxxxxxx : +(2 rows) + +\pset format wrapped +execute q; + ab | a ++ |+ bc ++ c |+ +-------------------+-------------------- + xx | yyyyyyyyyyyyyyyyyy + xxxx | yyyyyyyyyyyyyyyy + xxxxxx : yyyyyyyyyyyyyy + xxxxxxxx : yyyyyyyyyyyy + xxxxxxxxxx : yyyyyyyyyy + xxxxxxxxxxxx : yyyyyyyy + xxxxxxxxxxxxxx : yyyyyy + xxxxxxxxxxxxxxxx : yyyy + xxxxxxxxxxxxxxxxx : yy + x : + xxxxxxxxxxxxxxxxx + xxx +(2 rows) + +\pset border 2 +\pset format unaligned +execute q; +ab + +c|a +bc +xx|yyyyyyyyyyyyyyyyyy +xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +(2 rows) +\pset format aligned +execute q; ++----------------------+--------------------+ +| ab | a | +|+ |+ bc | +|+ c |+ | ++----------------------+--------------------+ +| xx | yyyyyyyyyyyyyyyyyy | +| xxxx | yyyyyyyyyyyyyyyy | +| xxxxxx : yyyyyyyyyyyyyy | +| xxxxxxxx : yyyyyyyyyyyy | +| xxxxxxxxxx : yyyyyyyyyy | +| xxxxxxxxxxxx : yyyyyyyy | +| xxxxxxxxxxxxxx : yyyyyy | +| xxxxxxxxxxxxxxxx : yyyy | +| xxxxxxxxxxxxxxxxxx : yy | +| xxxxxxxxxxxxxxxxxxxx : | ++----------------------+--------------------+ +(2 rows) + +\pset format wrapped +execute q; ++-----------------+--------------------+ +| ab | a | +|+ |+ bc | +|+ c |+ | ++-----------------+--------------------+ +| xx | yyyyyyyyyyyyyyyyyy | +| xxxx | yyyyyyyyyyyyyyyy | +| xxxxxx : yyyyyyyyyyyyyy | +| xxxxxxxx : yyyyyyyyyyyy | +| xxxxxxxxxx : yyyyyyyyyy | +| xxxxxxxxxxxx : yyyyyyyy | +| xxxxxxxxxxxxxx : yyyyyy | +| xxxxxxxxxxxxxxx : yyyy | +| x : yy | +| xxxxxxxxxxxxxxx : | +| xxx | +| xxxxxxxxxxxxxxx | +| xxxxx | ++-----------------+--------------------+ +(2 rows) + +\pset expanded on +\pset columns 20 +\pset border 0 +\pset format unaligned +execute q; +ab + +c|xx +a +bc|yyyyyyyyyyyyyyyyyy + +ab + +c|xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx +a +bc|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +\pset format aligned +execute q; +* Record 1 + ab xx ++ ++c + a yyyyyyyyyyyyyyyyyy ++bc +* Record 2 + ab xxxx ++ xxxxxx ++c xxxxxxxx + xxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxx + a yyyyyyyyyyyyyyyy ++bc yyyyyyyyyyyyyy + yyyyyyyyyyyy + yyyyyyyyyy + yyyyyyyy + yyyyyy + yyyy + yy + + +\pset format wrapped +execute q; +* Record 1 + ab xx ++ ++c + a yyyyyyyyyyyyyyyy ++bc yy +* Record 2 + ab xxxx ++ xxxxxx ++c xxxxxxxx + xxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxx + xx + xxxxxxxxxxxxxxxx + xxxx + a yyyyyyyyyyyyyyyy ++bc yyyyyyyyyyyyyy + yyyyyyyyyyyy + yyyyyyyyyy + yyyyyyyy + yyyyyy + yyyy + yy + + +\pset border 1 +\pset format unaligned +execute q; +ab + +c|xx +a +bc|yyyyyyyyyyyyyyyyyy + +ab + +c|xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx +a +bc|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +\pset format aligned +execute q; +-[ RECORD 1 ]------------- + ab | xx ++ ; ++c ; + a | yyyyyyyyyyyyyyyyyy ++bc ; +-[ RECORD 2 ]------------- + ab | xxxx ++ : xxxxxx ++c : xxxxxxxx + : xxxxxxxxxx + : xxxxxxxxxxxx + : xxxxxxxxxxxxxx + : xxxxxxxxxxxxxxxx + : xxxxxxxxxxxxxxxxxx + : xxxxxxxxxxxxxxxxxxxx + a | yyyyyyyyyyyyyyyy ++bc : yyyyyyyyyyyyyy + : yyyyyyyyyyyy + : yyyyyyyyyy + : yyyyyyyy + : yyyyyy + : yyyy + : yy + : + +\pset format wrapped +execute q; +-[ RECORD 1 ]------- + ab | xx ++ ; ++c ; + a | yyyyyyyyyyyyyy ++bc ; yyyy +-[ RECORD 2 ]------- + ab | xxxx ++ : xxxxxx ++c : xxxxxxxx + : xxxxxxxxxx + : xxxxxxxxxxxx + : xxxxxxxxxxxxxx + : xxxxxxxxxxxxxx + ; xx + : xxxxxxxxxxxxxx + ; xxxx + : xxxxxxxxxxxxxx + ; xxxxxx + a | yyyyyyyyyyyyyy ++bc ; yy + : yyyyyyyyyyyyyy + : yyyyyyyyyyyy + : yyyyyyyyyy + : yyyyyyyy + : yyyyyy + : yyyy + : yy + : + +\pset border 2 +\pset format unaligned +execute q; +ab + +c|xx +a +bc|yyyyyyyyyyyyyyyyyy + +ab + +c|xxxx +xxxxxx +xxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxxxxx +xxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxx +a +bc|yyyyyyyyyyyyyyyy +yyyyyyyyyyyyyy +yyyyyyyyyyyy +yyyyyyyyyy +yyyyyyyy +yyyyyy +yyyy +yy + +\pset format aligned +execute q; ++-[ RECORD 1 ]--------------+ +| ab | xx | +|+ ; | +|+c ; | +| a | yyyyyyyyyyyyyyyyyy | +|+bc ; | ++-[ RECORD 2 ]--------------+ +| ab | xxxx | +|+ : xxxxxx | +|+c : xxxxxxxx | +| : xxxxxxxxxx | +| : xxxxxxxxxxxx | +| : xxxxxxxxxxxxxx | +| : xxxxxxxxxxxxxxxx | +| : xxxxxxxxxxxxxxxxxx | +| : xxxxxxxxxxxxxxxxxxxx | +| a | yyyyyyyyyyyyyyyy | +|+bc : yyyyyyyyyyyyyy | +| : yyyyyyyyyyyy | +| : yyyyyyyyyy | +| : yyyyyyyy | +| : yyyyyy | +| : yyyy | +| : yy | +| : | ++----+----------------------+ + +\pset format wrapped +execute q; ++-[ RECORD 1 ]-----+ +| ab | xx | +|+ ; | +|+c ; | +| a | yyyyyyyyyyy | +|+bc ; yyyyyyy | ++-[ RECORD 2 ]-----+ +| ab | xxxx | +|+ : xxxxxx | +|+c : xxxxxxxx | +| : xxxxxxxxxx | +| : xxxxxxxxxxx | +| ; x | +| : xxxxxxxxxxx | +| ; xxx | +| : xxxxxxxxxxx | +| ; xxxxx | +| : xxxxxxxxxxx | +| ; xxxxxxx | +| : xxxxxxxxxxx | +| ; xxxxxxxxx | +| a | yyyyyyyyyyy | +|+bc ; yyyyy | +| : yyyyyyyyyyy | +| ; yyy | +| : yyyyyyyyyyy | +| ; y | +| : yyyyyyyyyy | +| : yyyyyyyy | +| : yyyyyy | +| : yyyy | +| : yy | +| : | ++----+-------------+ + +deallocate q; +-- test single-line header and data +prepare q as select repeat('x',2*n) as "0123456789abcdef", repeat('y',20-2*n) as "0123456789" from generate_series(1,10) as n; +\pset linestyle ascii +\pset expanded off +\pset columns 40 +\pset border 0 +\pset format unaligned +execute q; +0123456789abcdef|0123456789 +xx|yyyyyyyyyyyyyyyyyy +xxxx|yyyyyyyyyyyyyyyy +xxxxxx|yyyyyyyyyyyyyy +xxxxxxxx|yyyyyyyyyyyy +xxxxxxxxxx|yyyyyyyyyy +xxxxxxxxxxxx|yyyyyyyy +xxxxxxxxxxxxxx|yyyyyy +xxxxxxxxxxxxxxxx|yyyy +xxxxxxxxxxxxxxxxxx|yy +xxxxxxxxxxxxxxxxxxxx| +(10 rows) +\pset format aligned +execute q; + 0123456789abcdef 0123456789 +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx yyyyyyyyyyyyyyyy +xxxxxx yyyyyyyyyyyyyy +xxxxxxxx yyyyyyyyyyyy +xxxxxxxxxx yyyyyyyyyy +xxxxxxxxxxxx yyyyyyyy +xxxxxxxxxxxxxx yyyyyy +xxxxxxxxxxxxxxxx yyyy +xxxxxxxxxxxxxxxxxx yy +xxxxxxxxxxxxxxxxxxxx +(10 rows) + +\pset format wrapped +execute q; + 0123456789abcdef 0123456789 +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx yyyyyyyyyyyyyyyy +xxxxxx yyyyyyyyyyyyyy +xxxxxxxx yyyyyyyyyyyy +xxxxxxxxxx yyyyyyyyyy +xxxxxxxxxxxx yyyyyyyy +xxxxxxxxxxxxxx yyyyyy +xxxxxxxxxxxxxxxx yyyy +xxxxxxxxxxxxxxxxxx yy +xxxxxxxxxxxxxxxxxxxx +(10 rows) + +\pset border 1 +\pset format unaligned +execute q; +0123456789abcdef|0123456789 +xx|yyyyyyyyyyyyyyyyyy +xxxx|yyyyyyyyyyyyyyyy +xxxxxx|yyyyyyyyyyyyyy +xxxxxxxx|yyyyyyyyyyyy +xxxxxxxxxx|yyyyyyyyyy +xxxxxxxxxxxx|yyyyyyyy +xxxxxxxxxxxxxx|yyyyyy +xxxxxxxxxxxxxxxx|yyyy +xxxxxxxxxxxxxxxxxx|yy +xxxxxxxxxxxxxxxxxxxx| +(10 rows) +\pset format aligned +execute q; + 0123456789abcdef | 0123456789 +----------------------+-------------------- + xx | yyyyyyyyyyyyyyyyyy + xxxx | yyyyyyyyyyyyyyyy + xxxxxx | yyyyyyyyyyyyyy + xxxxxxxx | yyyyyyyyyyyy + xxxxxxxxxx | yyyyyyyyyy + xxxxxxxxxxxx | yyyyyyyy + xxxxxxxxxxxxxx | yyyyyy + xxxxxxxxxxxxxxxx | yyyy + xxxxxxxxxxxxxxxxxx | yy + xxxxxxxxxxxxxxxxxxxx | +(10 rows) + +\pset format wrapped +execute q; + 0123456789abcdef | 0123456789 +---------------------+------------------ + xx | yyyyyyyyyyyyyyyy. + |.yy + xxxx | yyyyyyyyyyyyyyyy + xxxxxx | yyyyyyyyyyyyyy + xxxxxxxx | yyyyyyyyyyyy + xxxxxxxxxx | yyyyyyyyyy + xxxxxxxxxxxx | yyyyyyyy + xxxxxxxxxxxxxx | yyyyyy + xxxxxxxxxxxxxxxx | yyyy + xxxxxxxxxxxxxxxxxx | yy + xxxxxxxxxxxxxxxxxxx.| +.x | +(10 rows) + +\pset border 2 +\pset format unaligned +execute q; +0123456789abcdef|0123456789 +xx|yyyyyyyyyyyyyyyyyy +xxxx|yyyyyyyyyyyyyyyy +xxxxxx|yyyyyyyyyyyyyy +xxxxxxxx|yyyyyyyyyyyy +xxxxxxxxxx|yyyyyyyyyy +xxxxxxxxxxxx|yyyyyyyy +xxxxxxxxxxxxxx|yyyyyy +xxxxxxxxxxxxxxxx|yyyy +xxxxxxxxxxxxxxxxxx|yy +xxxxxxxxxxxxxxxxxxxx| +(10 rows) +\pset format aligned +execute q; ++----------------------+--------------------+ +| 0123456789abcdef | 0123456789 | ++----------------------+--------------------+ +| xx | yyyyyyyyyyyyyyyyyy | +| xxxx | yyyyyyyyyyyyyyyy | +| xxxxxx | yyyyyyyyyyyyyy | +| xxxxxxxx | yyyyyyyyyyyy | +| xxxxxxxxxx | yyyyyyyyyy | +| xxxxxxxxxxxx | yyyyyyyy | +| xxxxxxxxxxxxxx | yyyyyy | +| xxxxxxxxxxxxxxxx | yyyy | +| xxxxxxxxxxxxxxxxxx | yy | +| xxxxxxxxxxxxxxxxxxxx | | ++----------------------+--------------------+ +(10 rows) + +\pset format wrapped +execute q; ++--------------------+-----------------+ +| 0123456789abcdef | 0123456789 | ++--------------------+-----------------+ +| xx | yyyyyyyyyyyyyyy.| +| |.yyy | +| xxxx | yyyyyyyyyyyyyyy.| +| |.y | +| xxxxxx | yyyyyyyyyyyyyy | +| xxxxxxxx | yyyyyyyyyyyy | +| xxxxxxxxxx | yyyyyyyyyy | +| xxxxxxxxxxxx | yyyyyyyy | +| xxxxxxxxxxxxxx | yyyyyy | +| xxxxxxxxxxxxxxxx | yyyy | +| xxxxxxxxxxxxxxxxxx | yy | +| xxxxxxxxxxxxxxxxxx.| | +|.xx | | ++--------------------+-----------------+ +(10 rows) + +\pset expanded on +\pset columns 30 +\pset border 0 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyyyyyyyyyyyyyyyyy +* Record 2 +0123456789abcdef xxxx +0123456789 yyyyyyyyyyyyyyyy +* Record 3 +0123456789abcdef xxxxxx +0123456789 yyyyyyyyyyyyyy +* Record 4 +0123456789abcdef xxxxxxxx +0123456789 yyyyyyyyyyyy +* Record 5 +0123456789abcdef xxxxxxxxxx +0123456789 yyyyyyyyyy +* Record 6 +0123456789abcdef xxxxxxxxxxxx +0123456789 yyyyyyyy +* Record 7 +0123456789abcdef xxxxxxxxxxxxxx +0123456789 yyyyyy +* Record 8 +0123456789abcdef xxxxxxxxxxxxxxxx +0123456789 yyyy +* Record 9 +0123456789abcdef xxxxxxxxxxxxxxxxxx +0123456789 yy +* Record 10 +0123456789abcdef xxxxxxxxxxxxxxxxxxxx +0123456789 + +\pset format wrapped +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyyyyyyyyyyy. + .yyyyyy +* Record 2 +0123456789abcdef xxxx +0123456789 yyyyyyyyyyyy. + .yyyy +* Record 3 +0123456789abcdef xxxxxx +0123456789 yyyyyyyyyyyy. + .yy +* Record 4 +0123456789abcdef xxxxxxxx +0123456789 yyyyyyyyyyyy +* Record 5 +0123456789abcdef xxxxxxxxxx +0123456789 yyyyyyyyyy +* Record 6 +0123456789abcdef xxxxxxxxxxxx +0123456789 yyyyyyyy +* Record 7 +0123456789abcdef xxxxxxxxxxxx. + .xx +0123456789 yyyyyy +* Record 8 +0123456789abcdef xxxxxxxxxxxx. + .xxxx +0123456789 yyyy +* Record 9 +0123456789abcdef xxxxxxxxxxxx. + .xxxxxx +0123456789 yy +* Record 10 +0123456789abcdef xxxxxxxxxxxx. + .xxxxxxxx +0123456789 + +\pset border 1 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +-[ RECORD 1 ]----+--------------------- +0123456789abcdef | xx +0123456789 | yyyyyyyyyyyyyyyyyy +-[ RECORD 2 ]----+--------------------- +0123456789abcdef | xxxx +0123456789 | yyyyyyyyyyyyyyyy +-[ RECORD 3 ]----+--------------------- +0123456789abcdef | xxxxxx +0123456789 | yyyyyyyyyyyyyy +-[ RECORD 4 ]----+--------------------- +0123456789abcdef | xxxxxxxx +0123456789 | yyyyyyyyyyyy +-[ RECORD 5 ]----+--------------------- +0123456789abcdef | xxxxxxxxxx +0123456789 | yyyyyyyyyy +-[ RECORD 6 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxx +0123456789 | yyyyyyyy +-[ RECORD 7 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxx +0123456789 | yyyyyy +-[ RECORD 8 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxx +0123456789 | yyyy +-[ RECORD 9 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxx +0123456789 | yy +-[ RECORD 10 ]---+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxxxx +0123456789 | + +\pset format wrapped +execute q; +-[ RECORD 1 ]----+----------- +0123456789abcdef | xx +0123456789 | yyyyyyyyyy. + |.yyyyyyyy +-[ RECORD 2 ]----+----------- +0123456789abcdef | xxxx +0123456789 | yyyyyyyyyy. + |.yyyyyy +-[ RECORD 3 ]----+----------- +0123456789abcdef | xxxxxx +0123456789 | yyyyyyyyyy. + |.yyyy +-[ RECORD 4 ]----+----------- +0123456789abcdef | xxxxxxxx +0123456789 | yyyyyyyyyy. + |.yy +-[ RECORD 5 ]----+----------- +0123456789abcdef | xxxxxxxxxx +0123456789 | yyyyyyyyyy +-[ RECORD 6 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xx +0123456789 | yyyyyyyy +-[ RECORD 7 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxx +0123456789 | yyyyyy +-[ RECORD 8 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxxxx +0123456789 | yyyy +-[ RECORD 9 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxxxxxx +0123456789 | yy +-[ RECORD 10 ]---+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxxxxxxxx +0123456789 | + +\pset border 2 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; ++-[ RECORD 1 ]-----+----------------------+ +| 0123456789abcdef | xx | +| 0123456789 | yyyyyyyyyyyyyyyyyy | ++-[ RECORD 2 ]-----+----------------------+ +| 0123456789abcdef | xxxx | +| 0123456789 | yyyyyyyyyyyyyyyy | ++-[ RECORD 3 ]-----+----------------------+ +| 0123456789abcdef | xxxxxx | +| 0123456789 | yyyyyyyyyyyyyy | ++-[ RECORD 4 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxx | +| 0123456789 | yyyyyyyyyyyy | ++-[ RECORD 5 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxx | +| 0123456789 | yyyyyyyyyy | ++-[ RECORD 6 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxx | +| 0123456789 | yyyyyyyy | ++-[ RECORD 7 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxx | +| 0123456789 | yyyyyy | ++-[ RECORD 8 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxx | +| 0123456789 | yyyy | ++-[ RECORD 9 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxx | +| 0123456789 | yy | ++-[ RECORD 10 ]----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxxxx | +| 0123456789 | | ++------------------+----------------------+ + +\pset format wrapped +execute q; ++-[ RECORD 1 ]-----+---------+ +| 0123456789abcdef | xx | +| 0123456789 | yyyyyyy.| +| |.yyyyyyy.| +| |.yyyy | ++-[ RECORD 2 ]-----+---------+ +| 0123456789abcdef | xxxx | +| 0123456789 | yyyyyyy.| +| |.yyyyyyy.| +| |.yy | ++-[ RECORD 3 ]-----+---------+ +| 0123456789abcdef | xxxxxx | +| 0123456789 | yyyyyyy.| +| |.yyyyyyy | ++-[ RECORD 4 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.x | +| 0123456789 | yyyyyyy.| +| |.yyyyy | ++-[ RECORD 5 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxx | +| 0123456789 | yyyyyyy.| +| |.yyy | ++-[ RECORD 6 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxx | +| 0123456789 | yyyyyyy.| +| |.y | ++-[ RECORD 7 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx | +| 0123456789 | yyyyyy | ++-[ RECORD 8 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx.| +| |.xx | +| 0123456789 | yyyy | ++-[ RECORD 9 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx.| +| |.xxxx | +| 0123456789 | yy | ++-[ RECORD 10 ]----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx.| +| |.xxxxxx | +| 0123456789 | | ++------------------+---------+ + +\pset expanded on +\pset columns 20 +\pset border 0 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyyyyyyyyyyyyyyyyy +* Record 2 +0123456789abcdef xxxx +0123456789 yyyyyyyyyyyyyyyy +* Record 3 +0123456789abcdef xxxxxx +0123456789 yyyyyyyyyyyyyy +* Record 4 +0123456789abcdef xxxxxxxx +0123456789 yyyyyyyyyyyy +* Record 5 +0123456789abcdef xxxxxxxxxx +0123456789 yyyyyyyyyy +* Record 6 +0123456789abcdef xxxxxxxxxxxx +0123456789 yyyyyyyy +* Record 7 +0123456789abcdef xxxxxxxxxxxxxx +0123456789 yyyyyy +* Record 8 +0123456789abcdef xxxxxxxxxxxxxxxx +0123456789 yyyy +* Record 9 +0123456789abcdef xxxxxxxxxxxxxxxxxx +0123456789 yy +* Record 10 +0123456789abcdef xxxxxxxxxxxxxxxxxxxx +0123456789 + +\pset format wrapped +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyy. + .yyy. + .yyy. + .yyy. + .yyy. + .yyy +* Record 2 +0123456789abcdef xxx. + .x +0123456789 yyy. + .yyy. + .yyy. + .yyy. + .yyy. + .y +* Record 3 +0123456789abcdef xxx. + .xxx +0123456789 yyy. + .yyy. + .yyy. + .yyy. + .yy +* Record 4 +0123456789abcdef xxx. + .xxx. + .xx +0123456789 yyy. + .yyy. + .yyy. + .yyy +* Record 5 +0123456789abcdef xxx. + .xxx. + .xxx. + .x +0123456789 yyy. + .yyy. + .yyy. + .y +* Record 6 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx +0123456789 yyy. + .yyy. + .yy +* Record 7 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. + .xx +0123456789 yyy. + .yyy +* Record 8 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. + .xxx. + .x +0123456789 yyy. + .y +* Record 9 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. + .xxx. + .xxx +0123456789 yy +* Record 10 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. + .xxx. + .xxx. + .xx +0123456789 + +\pset border 1 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +-[ RECORD 1 ]----+--------------------- +0123456789abcdef | xx +0123456789 | yyyyyyyyyyyyyyyyyy +-[ RECORD 2 ]----+--------------------- +0123456789abcdef | xxxx +0123456789 | yyyyyyyyyyyyyyyy +-[ RECORD 3 ]----+--------------------- +0123456789abcdef | xxxxxx +0123456789 | yyyyyyyyyyyyyy +-[ RECORD 4 ]----+--------------------- +0123456789abcdef | xxxxxxxx +0123456789 | yyyyyyyyyyyy +-[ RECORD 5 ]----+--------------------- +0123456789abcdef | xxxxxxxxxx +0123456789 | yyyyyyyyyy +-[ RECORD 6 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxx +0123456789 | yyyyyyyy +-[ RECORD 7 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxx +0123456789 | yyyyyy +-[ RECORD 8 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxx +0123456789 | yyyy +-[ RECORD 9 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxx +0123456789 | yy +-[ RECORD 10 ]---+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxxxx +0123456789 | + +\pset format wrapped +execute q; +-[ RECORD 1 ]----+---- +0123456789abcdef | xx +0123456789 | yyy. + |.yyy. + |.yyy. + |.yyy. + |.yyy. + |.yyy +-[ RECORD 2 ]----+---- +0123456789abcdef | xxx. + |.x +0123456789 | yyy. + |.yyy. + |.yyy. + |.yyy. + |.yyy. + |.y +-[ RECORD 3 ]----+---- +0123456789abcdef | xxx. + |.xxx +0123456789 | yyy. + |.yyy. + |.yyy. + |.yyy. + |.yy +-[ RECORD 4 ]----+---- +0123456789abcdef | xxx. + |.xxx. + |.xx +0123456789 | yyy. + |.yyy. + |.yyy. + |.yyy +-[ RECORD 5 ]----+---- +0123456789abcdef | xxx. + |.xxx. + |.xxx. + |.x +0123456789 | yyy. + |.yyy. + |.yyy. + |.y +-[ RECORD 6 ]----+---- +0123456789abcdef | xxx. + |.xxx. + |.xxx. + |.xxx +0123456789 | yyy. + |.yyy. + |.yy +-[ RECORD 7 ]----+---- +0123456789abcdef | xxx. + |.xxx. + |.xxx. + |.xxx. + |.xx +0123456789 | yyy. + |.yyy +-[ RECORD 8 ]----+---- +0123456789abcdef | xxx. + |.xxx. + |.xxx. + |.xxx. + |.xxx. + |.x +0123456789 | yyy. + |.y +-[ RECORD 9 ]----+---- +0123456789abcdef | xxx. + |.xxx. + |.xxx. + |.xxx. + |.xxx. + |.xxx +0123456789 | yy +-[ RECORD 10 ]---+---- +0123456789abcdef | xxx. + |.xxx. + |.xxx. + |.xxx. + |.xxx. + |.xxx. + |.xx +0123456789 | + +\pset border 2 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; ++-[ RECORD 1 ]-----+----------------------+ +| 0123456789abcdef | xx | +| 0123456789 | yyyyyyyyyyyyyyyyyy | ++-[ RECORD 2 ]-----+----------------------+ +| 0123456789abcdef | xxxx | +| 0123456789 | yyyyyyyyyyyyyyyy | ++-[ RECORD 3 ]-----+----------------------+ +| 0123456789abcdef | xxxxxx | +| 0123456789 | yyyyyyyyyyyyyy | ++-[ RECORD 4 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxx | +| 0123456789 | yyyyyyyyyyyy | ++-[ RECORD 5 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxx | +| 0123456789 | yyyyyyyyyy | ++-[ RECORD 6 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxx | +| 0123456789 | yyyyyyyy | ++-[ RECORD 7 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxx | +| 0123456789 | yyyyyy | ++-[ RECORD 8 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxx | +| 0123456789 | yyyy | ++-[ RECORD 9 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxx | +| 0123456789 | yy | ++-[ RECORD 10 ]----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxxxx | +| 0123456789 | | ++------------------+----------------------+ + +\pset format wrapped +execute q; ++-[ RECORD 1 ]-----+-----+ +| 0123456789abcdef | xx | +| 0123456789 | yyy.| +| |.yyy.| +| |.yyy.| +| |.yyy.| +| |.yyy.| +| |.yyy | ++-[ RECORD 2 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.x | +| 0123456789 | yyy.| +| |.yyy.| +| |.yyy.| +| |.yyy.| +| |.yyy.| +| |.y | ++-[ RECORD 3 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx | +| 0123456789 | yyy.| +| |.yyy.| +| |.yyy.| +| |.yyy.| +| |.yy | ++-[ RECORD 4 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx.| +| |.xx | +| 0123456789 | yyy.| +| |.yyy.| +| |.yyy.| +| |.yyy | ++-[ RECORD 5 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx.| +| |.xxx.| +| |.x | +| 0123456789 | yyy.| +| |.yyy.| +| |.yyy.| +| |.y | ++-[ RECORD 6 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx | +| 0123456789 | yyy.| +| |.yyy.| +| |.yy | ++-[ RECORD 7 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.xx | +| 0123456789 | yyy.| +| |.yyy | ++-[ RECORD 8 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.x | +| 0123456789 | yyy.| +| |.y | ++-[ RECORD 9 ]-----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx | +| 0123456789 | yy | ++-[ RECORD 10 ]----+-----+ +| 0123456789abcdef | xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.xxx.| +| |.xx | +| 0123456789 | | ++------------------+-----+ + +\pset linestyle old-ascii +\pset expanded off +\pset columns 40 +\pset border 0 +\pset format unaligned +execute q; +0123456789abcdef|0123456789 +xx|yyyyyyyyyyyyyyyyyy +xxxx|yyyyyyyyyyyyyyyy +xxxxxx|yyyyyyyyyyyyyy +xxxxxxxx|yyyyyyyyyyyy +xxxxxxxxxx|yyyyyyyyyy +xxxxxxxxxxxx|yyyyyyyy +xxxxxxxxxxxxxx|yyyyyy +xxxxxxxxxxxxxxxx|yyyy +xxxxxxxxxxxxxxxxxx|yy +xxxxxxxxxxxxxxxxxxxx| +(10 rows) +\pset format aligned +execute q; + 0123456789abcdef 0123456789 +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx yyyyyyyyyyyyyyyy +xxxxxx yyyyyyyyyyyyyy +xxxxxxxx yyyyyyyyyyyy +xxxxxxxxxx yyyyyyyyyy +xxxxxxxxxxxx yyyyyyyy +xxxxxxxxxxxxxx yyyyyy +xxxxxxxxxxxxxxxx yyyy +xxxxxxxxxxxxxxxxxx yy +xxxxxxxxxxxxxxxxxxxx +(10 rows) + +\pset format wrapped +execute q; + 0123456789abcdef 0123456789 +-------------------- ------------------ +xx yyyyyyyyyyyyyyyyyy +xxxx yyyyyyyyyyyyyyyy +xxxxxx yyyyyyyyyyyyyy +xxxxxxxx yyyyyyyyyyyy +xxxxxxxxxx yyyyyyyyyy +xxxxxxxxxxxx yyyyyyyy +xxxxxxxxxxxxxx yyyyyy +xxxxxxxxxxxxxxxx yyyy +xxxxxxxxxxxxxxxxxx yy +xxxxxxxxxxxxxxxxxxxx +(10 rows) + +\pset border 1 +\pset format unaligned +execute q; +0123456789abcdef|0123456789 +xx|yyyyyyyyyyyyyyyyyy +xxxx|yyyyyyyyyyyyyyyy +xxxxxx|yyyyyyyyyyyyyy +xxxxxxxx|yyyyyyyyyyyy +xxxxxxxxxx|yyyyyyyyyy +xxxxxxxxxxxx|yyyyyyyy +xxxxxxxxxxxxxx|yyyyyy +xxxxxxxxxxxxxxxx|yyyy +xxxxxxxxxxxxxxxxxx|yy +xxxxxxxxxxxxxxxxxxxx| +(10 rows) +\pset format aligned +execute q; + 0123456789abcdef | 0123456789 +----------------------+-------------------- + xx | yyyyyyyyyyyyyyyyyy + xxxx | yyyyyyyyyyyyyyyy + xxxxxx | yyyyyyyyyyyyyy + xxxxxxxx | yyyyyyyyyyyy + xxxxxxxxxx | yyyyyyyyyy + xxxxxxxxxxxx | yyyyyyyy + xxxxxxxxxxxxxx | yyyyyy + xxxxxxxxxxxxxxxx | yyyy + xxxxxxxxxxxxxxxxxx | yy + xxxxxxxxxxxxxxxxxxxx | +(10 rows) + +\pset format wrapped +execute q; + 0123456789abcdef | 0123456789 +---------------------+------------------ + xx | yyyyyyyyyyyyyyyy + ; yy + xxxx | yyyyyyyyyyyyyyyy + xxxxxx | yyyyyyyyyyyyyy + xxxxxxxx | yyyyyyyyyyyy + xxxxxxxxxx | yyyyyyyyyy + xxxxxxxxxxxx | yyyyyyyy + xxxxxxxxxxxxxx | yyyyyy + xxxxxxxxxxxxxxxx | yyyy + xxxxxxxxxxxxxxxxxx | yy + xxxxxxxxxxxxxxxxxxx | + x +(10 rows) + +\pset border 2 +\pset format unaligned +execute q; +0123456789abcdef|0123456789 +xx|yyyyyyyyyyyyyyyyyy +xxxx|yyyyyyyyyyyyyyyy +xxxxxx|yyyyyyyyyyyyyy +xxxxxxxx|yyyyyyyyyyyy +xxxxxxxxxx|yyyyyyyyyy +xxxxxxxxxxxx|yyyyyyyy +xxxxxxxxxxxxxx|yyyyyy +xxxxxxxxxxxxxxxx|yyyy +xxxxxxxxxxxxxxxxxx|yy +xxxxxxxxxxxxxxxxxxxx| +(10 rows) +\pset format aligned +execute q; ++----------------------+--------------------+ +| 0123456789abcdef | 0123456789 | ++----------------------+--------------------+ +| xx | yyyyyyyyyyyyyyyyyy | +| xxxx | yyyyyyyyyyyyyyyy | +| xxxxxx | yyyyyyyyyyyyyy | +| xxxxxxxx | yyyyyyyyyyyy | +| xxxxxxxxxx | yyyyyyyyyy | +| xxxxxxxxxxxx | yyyyyyyy | +| xxxxxxxxxxxxxx | yyyyyy | +| xxxxxxxxxxxxxxxx | yyyy | +| xxxxxxxxxxxxxxxxxx | yy | +| xxxxxxxxxxxxxxxxxxxx | | ++----------------------+--------------------+ +(10 rows) + +\pset format wrapped +execute q; ++--------------------+-----------------+ +| 0123456789abcdef | 0123456789 | ++--------------------+-----------------+ +| xx | yyyyyyyyyyyyyyy | +| ; yyy | +| xxxx | yyyyyyyyyyyyyyy | +| ; y | +| xxxxxx | yyyyyyyyyyyyyy | +| xxxxxxxx | yyyyyyyyyyyy | +| xxxxxxxxxx | yyyyyyyyyy | +| xxxxxxxxxxxx | yyyyyyyy | +| xxxxxxxxxxxxxx | yyyyyy | +| xxxxxxxxxxxxxxxx | yyyy | +| xxxxxxxxxxxxxxxxxx | yy | +| xxxxxxxxxxxxxxxxxx | | +| xx | ++--------------------+-----------------+ +(10 rows) + +\pset expanded on +\pset border 0 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyyyyyyyyyyyyyyyyy +* Record 2 +0123456789abcdef xxxx +0123456789 yyyyyyyyyyyyyyyy +* Record 3 +0123456789abcdef xxxxxx +0123456789 yyyyyyyyyyyyyy +* Record 4 +0123456789abcdef xxxxxxxx +0123456789 yyyyyyyyyyyy +* Record 5 +0123456789abcdef xxxxxxxxxx +0123456789 yyyyyyyyyy +* Record 6 +0123456789abcdef xxxxxxxxxxxx +0123456789 yyyyyyyy +* Record 7 +0123456789abcdef xxxxxxxxxxxxxx +0123456789 yyyyyy +* Record 8 +0123456789abcdef xxxxxxxxxxxxxxxx +0123456789 yyyy +* Record 9 +0123456789abcdef xxxxxxxxxxxxxxxxxx +0123456789 yy +* Record 10 +0123456789abcdef xxxxxxxxxxxxxxxxxxxx +0123456789 + +\pset format wrapped +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyyyyyyyyyyyyyyyyy +* Record 2 +0123456789abcdef xxxx +0123456789 yyyyyyyyyyyyyyyy +* Record 3 +0123456789abcdef xxxxxx +0123456789 yyyyyyyyyyyyyy +* Record 4 +0123456789abcdef xxxxxxxx +0123456789 yyyyyyyyyyyy +* Record 5 +0123456789abcdef xxxxxxxxxx +0123456789 yyyyyyyyyy +* Record 6 +0123456789abcdef xxxxxxxxxxxx +0123456789 yyyyyyyy +* Record 7 +0123456789abcdef xxxxxxxxxxxxxx +0123456789 yyyyyy +* Record 8 +0123456789abcdef xxxxxxxxxxxxxxxx +0123456789 yyyy +* Record 9 +0123456789abcdef xxxxxxxxxxxxxxxxxx +0123456789 yy +* Record 10 +0123456789abcdef xxxxxxxxxxxxxxxxxxxx +0123456789 + +\pset border 1 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +-[ RECORD 1 ]----+--------------------- +0123456789abcdef | xx +0123456789 | yyyyyyyyyyyyyyyyyy +-[ RECORD 2 ]----+--------------------- +0123456789abcdef | xxxx +0123456789 | yyyyyyyyyyyyyyyy +-[ RECORD 3 ]----+--------------------- +0123456789abcdef | xxxxxx +0123456789 | yyyyyyyyyyyyyy +-[ RECORD 4 ]----+--------------------- +0123456789abcdef | xxxxxxxx +0123456789 | yyyyyyyyyyyy +-[ RECORD 5 ]----+--------------------- +0123456789abcdef | xxxxxxxxxx +0123456789 | yyyyyyyyyy +-[ RECORD 6 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxx +0123456789 | yyyyyyyy +-[ RECORD 7 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxx +0123456789 | yyyyyy +-[ RECORD 8 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxx +0123456789 | yyyy +-[ RECORD 9 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxx +0123456789 | yy +-[ RECORD 10 ]---+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxxxx +0123456789 | + +\pset format wrapped +execute q; +-[ RECORD 1 ]----+--------------------- +0123456789abcdef | xx +0123456789 | yyyyyyyyyyyyyyyyyy +-[ RECORD 2 ]----+--------------------- +0123456789abcdef | xxxx +0123456789 | yyyyyyyyyyyyyyyy +-[ RECORD 3 ]----+--------------------- +0123456789abcdef | xxxxxx +0123456789 | yyyyyyyyyyyyyy +-[ RECORD 4 ]----+--------------------- +0123456789abcdef | xxxxxxxx +0123456789 | yyyyyyyyyyyy +-[ RECORD 5 ]----+--------------------- +0123456789abcdef | xxxxxxxxxx +0123456789 | yyyyyyyyyy +-[ RECORD 6 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxx +0123456789 | yyyyyyyy +-[ RECORD 7 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxx +0123456789 | yyyyyy +-[ RECORD 8 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxx +0123456789 | yyyy +-[ RECORD 9 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxx +0123456789 | yy +-[ RECORD 10 ]---+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxxxx +0123456789 | + +\pset border 2 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; ++-[ RECORD 1 ]-----+----------------------+ +| 0123456789abcdef | xx | +| 0123456789 | yyyyyyyyyyyyyyyyyy | ++-[ RECORD 2 ]-----+----------------------+ +| 0123456789abcdef | xxxx | +| 0123456789 | yyyyyyyyyyyyyyyy | ++-[ RECORD 3 ]-----+----------------------+ +| 0123456789abcdef | xxxxxx | +| 0123456789 | yyyyyyyyyyyyyy | ++-[ RECORD 4 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxx | +| 0123456789 | yyyyyyyyyyyy | ++-[ RECORD 5 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxx | +| 0123456789 | yyyyyyyyyy | ++-[ RECORD 6 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxx | +| 0123456789 | yyyyyyyy | ++-[ RECORD 7 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxx | +| 0123456789 | yyyyyy | ++-[ RECORD 8 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxx | +| 0123456789 | yyyy | ++-[ RECORD 9 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxx | +| 0123456789 | yy | ++-[ RECORD 10 ]----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxxxx | +| 0123456789 | | ++------------------+----------------------+ + +\pset format wrapped +execute q; ++-[ RECORD 1 ]-----+-------------------+ +| 0123456789abcdef | xx | +| 0123456789 | yyyyyyyyyyyyyyyyy | +| ; y | ++-[ RECORD 2 ]-----+-------------------+ +| 0123456789abcdef | xxxx | +| 0123456789 | yyyyyyyyyyyyyyyy | ++-[ RECORD 3 ]-----+-------------------+ +| 0123456789abcdef | xxxxxx | +| 0123456789 | yyyyyyyyyyyyyy | ++-[ RECORD 4 ]-----+-------------------+ +| 0123456789abcdef | xxxxxxxx | +| 0123456789 | yyyyyyyyyyyy | ++-[ RECORD 5 ]-----+-------------------+ +| 0123456789abcdef | xxxxxxxxxx | +| 0123456789 | yyyyyyyyyy | ++-[ RECORD 6 ]-----+-------------------+ +| 0123456789abcdef | xxxxxxxxxxxx | +| 0123456789 | yyyyyyyy | ++-[ RECORD 7 ]-----+-------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxx | +| 0123456789 | yyyyyy | ++-[ RECORD 8 ]-----+-------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxx | +| 0123456789 | yyyy | ++-[ RECORD 9 ]-----+-------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxx | +| ; x | +| 0123456789 | yy | ++-[ RECORD 10 ]----+-------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxx | +| ; xxx | +| 0123456789 | | ++------------------+-------------------+ + +deallocate q; +\pset linestyle ascii +\pset border 1 +-- support table for output-format tests (useful to create a footer) +create table psql_serial_tab (id serial); +-- test header/footer/tuples_only behavior in aligned/unaligned/wrapped cases +\pset format aligned +\pset expanded off +\d psql_serial_tab_id_seq + Sequence "public.psql_serial_tab_id_seq" + Type | Start | Minimum | Maximum | Increment | Cycles? | Cache +---------+-------+---------+------------+-----------+---------+------- + integer | 1 | 1 | 2147483647 | 1 | no | 1 +Owned by: public.psql_serial_tab.id + +\pset tuples_only true +\df exp + pg_catalog | exp | double precision | double precision | func + pg_catalog | exp | numeric | numeric | func + +\dfx exp +Schema | pg_catalog +Name | exp +Result data type | double precision +Argument data types | double precision +Type | func +--------------------+----------------- +Schema | pg_catalog +Name | exp +Result data type | numeric +Argument data types | numeric +Type | func + +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq +Sequence "public.psql_serial_tab_id_seq" +-[ RECORD 1 ]--------- +Type | integer +Start | 1 +Minimum | 1 +Maximum | 2147483647 +Increment | 1 +Cycles? | no +Cache | 1 + +Owned by: public.psql_serial_tab.id + +\pset tuples_only true +\df exp +Schema | pg_catalog +Name | exp +Result data type | double precision +Argument data types | double precision +Type | func +--------------------+----------------- +Schema | pg_catalog +Name | exp +Result data type | numeric +Argument data types | numeric +Type | func + +\pset tuples_only false +-- empty table is a special case for this format +select 1 where false; +(0 rows) + +\pset format unaligned +\pset expanded off +\d psql_serial_tab_id_seq +Sequence "public.psql_serial_tab_id_seq" +Type|Start|Minimum|Maximum|Increment|Cycles?|Cache +integer|1|1|2147483647|1|no|1 +Owned by: public.psql_serial_tab.id +\pset tuples_only true +\df exp +pg_catalog|exp|double precision|double precision|func +pg_catalog|exp|numeric|numeric|func +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq +Sequence "public.psql_serial_tab_id_seq" + +Type|integer +Start|1 +Minimum|1 +Maximum|2147483647 +Increment|1 +Cycles?|no +Cache|1 + +Owned by: public.psql_serial_tab.id +\pset tuples_only true +\df exp +Schema|pg_catalog +Name|exp +Result data type|double precision +Argument data types|double precision +Type|func + +Schema|pg_catalog +Name|exp +Result data type|numeric +Argument data types|numeric +Type|func +\pset tuples_only false +\pset format wrapped +\pset expanded off +\d psql_serial_tab_id_seq + Sequence "public.psql_serial_tab_id_seq" + Type | Start | Minimum | Maximum | Increment | Cycles? | Cache +---------+-------+---------+------------+-----------+---------+------- + integer | 1 | 1 | 2147483647 | 1 | no | 1 +Owned by: public.psql_serial_tab.id + +\pset tuples_only true +\df exp + pg_catalog | exp | double precision | double precision | func + pg_catalog | exp | numeric | numeric | func + +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq +Sequence "public.psql_serial_tab_id_seq" +-[ RECORD 1 ]--------- +Type | integer +Start | 1 +Minimum | 1 +Maximum | 2147483647 +Increment | 1 +Cycles? | no +Cache | 1 + +Owned by: public.psql_serial_tab.id + +\pset tuples_only true +\df exp +Schema | pg_catalog +Name | exp +Result data type | double precision +Argument data types | double precision +Type | func +--------------------+----------------- +Schema | pg_catalog +Name | exp +Result data type | numeric +Argument data types | numeric +Type | func + +\pset tuples_only false +-- check conditional am display +\pset expanded off +CREATE SCHEMA tableam_display; +CREATE ROLE regress_display_role; +ALTER SCHEMA tableam_display OWNER TO regress_display_role; +SET search_path TO tableam_display; +CREATE ACCESS METHOD heap_psql TYPE TABLE HANDLER heap_tableam_handler; +SET ROLE TO regress_display_role; +-- Use only relations with a physical size of zero. +CREATE TABLE tbl_heap_psql(f1 int, f2 char(100)) using heap_psql; +CREATE TABLE tbl_heap(f1 int, f2 char(100)) using heap; +CREATE VIEW view_heap_psql AS SELECT f1 from tbl_heap_psql; +CREATE MATERIALIZED VIEW mat_view_heap_psql USING heap_psql AS SELECT f1 from tbl_heap_psql; +\d+ tbl_heap_psql + Table "tableam_display.tbl_heap_psql" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+----------------+-----------+----------+---------+----------+--------------+------------- + f1 | integer | | | | plain | | + f2 | character(100) | | | | extended | | + +\d+ tbl_heap + Table "tableam_display.tbl_heap" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+----------------+-----------+----------+---------+----------+--------------+------------- + f1 | integer | | | | plain | | + f2 | character(100) | | | | extended | | + +\set HIDE_TABLEAM off +\d+ tbl_heap_psql + Table "tableam_display.tbl_heap_psql" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+----------------+-----------+----------+---------+----------+--------------+------------- + f1 | integer | | | | plain | | + f2 | character(100) | | | | extended | | +Access method: heap_psql + +\d+ tbl_heap + Table "tableam_display.tbl_heap" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+----------------+-----------+----------+---------+----------+--------------+------------- + f1 | integer | | | | plain | | + f2 | character(100) | | | | extended | | +Access method: heap + +-- AM is displayed for tables, indexes and materialized views. +\d+ + List of relations + Schema | Name | Type | Owner | Persistence | Access method | Size | Description +-----------------+--------------------+-------------------+----------------------+-------------+---------------+---------+------------- + tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent | heap_psql | 0 bytes | + tableam_display | tbl_heap | table | regress_display_role | permanent | heap | 0 bytes | + tableam_display | tbl_heap_psql | table | regress_display_role | permanent | heap_psql | 0 bytes | + tableam_display | view_heap_psql | view | regress_display_role | permanent | | 0 bytes | +(4 rows) + +\dt+ + List of tables + Schema | Name | Type | Owner | Persistence | Access method | Size | Description +-----------------+---------------+-------+----------------------+-------------+---------------+---------+------------- + tableam_display | tbl_heap | table | regress_display_role | permanent | heap | 0 bytes | + tableam_display | tbl_heap_psql | table | regress_display_role | permanent | heap_psql | 0 bytes | +(2 rows) + +\dm+ + List of materialized views + Schema | Name | Type | Owner | Persistence | Access method | Size | Description +-----------------+--------------------+-------------------+----------------------+-------------+---------------+---------+------------- + tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent | heap_psql | 0 bytes | +(1 row) + +-- But not for views and sequences. +\dv+ + List of views + Schema | Name | Type | Owner | Persistence | Size | Description +-----------------+----------------+------+----------------------+-------------+---------+------------- + tableam_display | view_heap_psql | view | regress_display_role | permanent | 0 bytes | +(1 row) + +\set HIDE_TABLEAM on +\d+ + List of relations + Schema | Name | Type | Owner | Persistence | Size | Description +-----------------+--------------------+-------------------+----------------------+-------------+---------+------------- + tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent | 0 bytes | + tableam_display | tbl_heap | table | regress_display_role | permanent | 0 bytes | + tableam_display | tbl_heap_psql | table | regress_display_role | permanent | 0 bytes | + tableam_display | view_heap_psql | view | regress_display_role | permanent | 0 bytes | +(4 rows) + +-- \d with 'x' enables expanded mode, but only without a pattern +\d+x tbl_heap + Table "tableam_display.tbl_heap" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+----------------+-----------+----------+---------+----------+--------------+------------- + f1 | integer | | | | plain | | + f2 | character(100) | | | | extended | | + +\d+x +List of relations +-[ RECORD 1 ]--------------------- +Schema | tableam_display +Name | mat_view_heap_psql +Type | materialized view +Owner | regress_display_role +Persistence | permanent +Size | 0 bytes +Description | +-[ RECORD 2 ]--------------------- +Schema | tableam_display +Name | tbl_heap +Type | table +Owner | regress_display_role +Persistence | permanent +Size | 0 bytes +Description | +-[ RECORD 3 ]--------------------- +Schema | tableam_display +Name | tbl_heap_psql +Type | table +Owner | regress_display_role +Persistence | permanent +Size | 0 bytes +Description | +-[ RECORD 4 ]--------------------- +Schema | tableam_display +Name | view_heap_psql +Type | view +Owner | regress_display_role +Persistence | permanent +Size | 0 bytes +Description | + +RESET ROLE; +RESET search_path; +DROP SCHEMA tableam_display CASCADE; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table tableam_display.tbl_heap_psql +drop cascades to table tableam_display.tbl_heap +drop cascades to view tableam_display.view_heap_psql +drop cascades to materialized view tableam_display.mat_view_heap_psql +DROP ACCESS METHOD heap_psql; +DROP ROLE regress_display_role; +-- test numericlocale (as best we can without control of psql's locale) +\pset format aligned +\pset expanded off +\pset numericlocale true +select n, -n as m, n * 111 as x, '1e90'::float8 as f +from generate_series(0,3) n; + n | m | x | f +---+----+-----+------- + 0 | 0 | 0 | 1e+90 + 1 | -1 | 111 | 1e+90 + 2 | -2 | 222 | 1e+90 + 3 | -3 | 333 | 1e+90 +(4 rows) + +\pset numericlocale false +-- test asciidoc output format +\pset format asciidoc +\pset border 1 +\pset expanded off +\d psql_serial_tab_id_seq + +.Sequence "public.psql_serial_tab_id_seq" +[options="header",cols="l,>l,>l,>l,l",frame="none"] +|==== +^l|Type ^l|Start ^l|Minimum ^l|Maximum ^l|Increment ^l|Cycles? ^l|Cache +|integer |1 |1 |2147483647 |1 |no |1 +|==== + +.... +Owned by: public.psql_serial_tab.id +.... +\pset tuples_only true +\df exp + +[cols="l|1 +l|1 +l|2147483647 +l|1 +l|1 +|==== + +.... +Owned by: public.psql_serial_tab.id +.... +\pset tuples_only true +\df exp + +[cols="h,l",frame="none"] +|==== +2+| +l|1 +2+^|Record 2 +l|2 +|==== +\pset border 1 +execute q; + +[cols="h,l",frame="none"] +|==== +2+^|Record 1 +l|1 +2+^|Record 2 +l|2 +|==== +\pset border 2 +execute q; + +[cols="h,l",frame="all",grid="all"] +|==== +2+^|Record 1 +l|1 +2+^|Record 2 +l|2 +|==== +deallocate q; +-- test csv output format +\pset format csv +\pset border 1 +\pset expanded off +\d psql_serial_tab_id_seq +Type,Start,Minimum,Maximum,Increment,Cycles?,Cache +integer,1,1,2147483647,1,no,1 +\pset tuples_only true +\df exp +pg_catalog,exp,double precision,double precision,func +pg_catalog,exp,numeric,numeric,func +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq +Type,integer +Start,1 +Minimum,1 +Maximum,2147483647 +Increment,1 +Cycles?,no +Cache,1 +\pset tuples_only true +\df exp +Schema,pg_catalog +Name,exp +Result data type,double precision +Argument data types,double precision +Type,func +Schema,pg_catalog +Name,exp +Result data type,numeric +Argument data types,numeric +Type,func +\pset tuples_only false +prepare q as + select 'some"text' as "a""title", E' \n' as "junk", + ' ' as "empty", n as int + from generate_series(1,2) as n; +\pset expanded off +execute q; +"a""title",junk,empty,int +"some""text"," +", ,1 +"some""text"," +", ,2 +\pset expanded on +execute q; +"a""title","some""text" +junk," +" +empty, +int,1 +"a""title","some""text" +junk," +" +empty, +int,2 +deallocate q; +-- special cases +\pset expanded off +select 'comma,comma' as comma, 'semi;semi' as semi; +comma,semi +"comma,comma",semi;semi +\pset csv_fieldsep ';' +select 'comma,comma' as comma, 'semi;semi' as semi; +comma;semi +comma,comma;"semi;semi" +select '\.' as data; +data +"\." +\pset csv_fieldsep '.' +select '\' as d1, '' as d2; +"d1"."d2" +"\"."" +-- illegal csv separators +\pset csv_fieldsep '' +\pset: csv_fieldsep must be a single one-byte character +\pset csv_fieldsep '\0' +\pset: csv_fieldsep must be a single one-byte character +\pset csv_fieldsep '\n' +\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return +\pset csv_fieldsep '\r' +\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return +\pset csv_fieldsep '"' +\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return +\pset csv_fieldsep ',,' +\pset: csv_fieldsep must be a single one-byte character +\pset csv_fieldsep ',' +-- test html output format +\pset format html +\pset border 1 +\pset expanded off +\d psql_serial_tab_id_seq + + + + + + + + + + + + + + + + + + + + +
Sequence "public.psql_serial_tab_id_seq"
TypeStartMinimumMaximumIncrementCycles?Cache
integer1121474836471no1
+

Owned by: public.psql_serial_tab.id
+

+\pset tuples_only true +\df exp + + + + + + + + + + + + + + + +
pg_catalogexpdouble precisiondouble precisionfunc
pg_catalogexpnumericnumericfunc
+ +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Sequence "public.psql_serial_tab_id_seq"
Record 1
Typeinteger
Start1
Minimum1
Maximum2147483647
Increment1
Cycles?no
Cache1
+

Owned by: public.psql_serial_tab.id
+

+\pset tuples_only true +\df exp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
Schemapg_catalog
Nameexp
Result data typedouble precision
Argument data typesdouble precision
Typefunc
 
Schemapg_catalog
Nameexp
Result data typenumeric
Argument data typesnumeric
Typefunc
+ +\pset tuples_only false +prepare q as + select 'some"text' as "a&title", E' \n' as "junk", + ' ' as "empty", n as int + from generate_series(1,2) as n; +\pset expanded off +\pset border 0 +execute q; + + + + + + + + + + + + + + + + + + + +
a&titlejunkemptyint
some"text  <foo>
+<bar>
  1
some"text  <foo>
+<bar>
  2
+

(2 rows)
+

+\pset border 1 +execute q; + + + + + + + + + + + + + + + + + + + +
a&titlejunkemptyint
some"text  <foo>
+<bar>
  1
some"text  <foo>
+<bar>
  2
+

(2 rows)
+

+\pset tableattr foobar +execute q; + + + + + + + + + + + + + + + + + + + +
a&titlejunkemptyint
some"text  <foo>
+<bar>
  1
some"text  <foo>
+<bar>
  2
+

(2 rows)
+

+\pset tableattr +\pset expanded on +\pset border 0 +execute q; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record 1
a&titlesome"text
junk  <foo>
+<bar>
empty 
int1
Record 2
a&titlesome"text
junk  <foo>
+<bar>
empty 
int2
+ +\pset border 1 +execute q; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record 1
a&titlesome"text
junk  <foo>
+<bar>
empty 
int1
Record 2
a&titlesome"text
junk  <foo>
+<bar>
empty 
int2
+ +\pset tableattr foobar +execute q; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record 1
a&titlesome"text
junk  <foo>
+<bar>
empty 
int1
Record 2
a&titlesome"text
junk  <foo>
+<bar>
empty 
int2
+ +\pset tableattr +deallocate q; +-- test latex output format +\pset format latex +\pset border 1 +\pset expanded off +\d psql_serial_tab_id_seq +\begin{center} +Sequence "public.psql\_serial\_tab\_id\_seq" +\end{center} + +\begin{tabular}{l | r | r | r | r | l | r} +\textit{Type} & \textit{Start} & \textit{Minimum} & \textit{Maximum} & \textit{Increment} & \textit{Cycles?} & \textit{Cache} \\ +\hline +integer & 1 & 1 & 2147483647 & 1 & no & 1 \\ +\end{tabular} + +\noindent Owned by: public.psql\_serial\_tab.id \\ + +\pset tuples_only true +\df exp +\begin{tabular}{l | l | l | l | l} +pg\_catalog & exp & double precision & double precision & func \\ +pg\_catalog & exp & numeric & numeric & func \\ +\end{tabular} + +\noindent +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq +\begin{center} +Sequence "public.psql\_serial\_tab\_id\_seq" +\end{center} + +\begin{tabular}{c|l} +\multicolumn{2}{c}{\textit{Record 1}} \\ +\hline +Type & integer \\ +Start & 1 \\ +Minimum & 1 \\ +Maximum & 2147483647 \\ +Increment & 1 \\ +Cycles? & no \\ +Cache & 1 \\ +\end{tabular} + +\noindent Owned by: public.psql\_serial\_tab.id \\ + +\pset tuples_only true +\df exp +\begin{tabular}{c|l} +\hline +Schema & pg\_catalog \\ +Name & exp \\ +Result data type & double precision \\ +Argument data types & double precision \\ +Type & func \\ +\hline +Schema & pg\_catalog \\ +Name & exp \\ +Result data type & numeric \\ +Argument data types & numeric \\ +Type & func \\ +\end{tabular} + +\noindent +\pset tuples_only false +prepare q as + select 'some\more_text' as "a$title", E' #%&^~|\n{bar}' as "junk", + ' ' as "empty", n as int + from generate_series(1,2) as n; +\pset expanded off +\pset border 0 +execute q; +\begin{tabular}{lllr} +\textit{a\$title} & \textit{junk} & \textit{empty} & \textit{int} \\ +\hline +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 1 \\ +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 2 \\ +\end{tabular} + +\noindent (2 rows) \\ + +\pset border 1 +execute q; +\begin{tabular}{l | l | l | r} +\textit{a\$title} & \textit{junk} & \textit{empty} & \textit{int} \\ +\hline +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 1 \\ +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 2 \\ +\end{tabular} + +\noindent (2 rows) \\ + +\pset border 2 +execute q; +\begin{tabular}{| l | l | l | r |} +\hline +\textit{a\$title} & \textit{junk} & \textit{empty} & \textit{int} \\ +\hline +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 1 \\ +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 2 \\ +\hline +\end{tabular} + +\noindent (2 rows) \\ + +\pset border 3 +execute q; +\begin{tabular}{| l | l | l | r |} +\hline +\textit{a\$title} & \textit{junk} & \textit{empty} & \textit{int} \\ +\hline +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 1 \\ +\hline +some\textbackslash{}more\_text & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} & & 2 \\ +\hline +\end{tabular} + +\noindent (2 rows) \\ + +\pset expanded on +\pset border 0 +execute q; +\begin{tabular}{cl} +\multicolumn{2}{c}{\textit{Record 1}} \\ +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\multicolumn{2}{c}{\textit{Record 2}} \\ +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\end{tabular} + +\noindent +\pset border 1 +execute q; +\begin{tabular}{c|l} +\multicolumn{2}{c}{\textit{Record 1}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\multicolumn{2}{c}{\textit{Record 2}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\end{tabular} + +\noindent +\pset border 2 +execute q; +\begin{tabular}{|c|l|} +\hline +\multicolumn{2}{|c|}{\textit{Record 1}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\hline +\multicolumn{2}{|c|}{\textit{Record 2}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\hline +\end{tabular} + +\noindent +\pset border 3 +execute q; +\begin{tabular}{|c|l|} +\hline +\multicolumn{2}{|c|}{\textit{Record 1}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\hline +\multicolumn{2}{|c|}{\textit{Record 2}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\hline +\end{tabular} + +\noindent +deallocate q; +-- test latex-longtable output format +\pset format latex-longtable +\pset border 1 +\pset expanded off +\d psql_serial_tab_id_seq +\begin{longtable}{l | r | r | r | r | l | r} +\small\textbf{\textit{Type}} & \small\textbf{\textit{Start}} & \small\textbf{\textit{Minimum}} & \small\textbf{\textit{Maximum}} & \small\textbf{\textit{Increment}} & \small\textbf{\textit{Cycles?}} & \small\textbf{\textit{Cache}} \\ +\midrule +\endfirsthead +\small\textbf{\textit{Type}} & \small\textbf{\textit{Start}} & \small\textbf{\textit{Minimum}} & \small\textbf{\textit{Maximum}} & \small\textbf{\textit{Increment}} & \small\textbf{\textit{Cycles?}} & \small\textbf{\textit{Cache}} \\ +\midrule +\endhead +\caption[Sequence "public.psql\_serial\_tab\_id\_seq" (Continued)]{Sequence "public.psql\_serial\_tab\_id\_seq"} +\endfoot +\caption[Sequence "public.psql\_serial\_tab\_id\_seq"]{Sequence "public.psql\_serial\_tab\_id\_seq"} +\endlastfoot +\raggedright{integer} +& +\raggedright{1} +& +\raggedright{1} +& +\raggedright{2147483647} +& +\raggedright{1} +& +\raggedright{no} +& +\raggedright{1} \tabularnewline +\end{longtable} +\pset tuples_only true +\df exp +\begin{longtable}{l | l | l | l | l} +\raggedright{pg\_catalog} +& +\raggedright{exp} +& +\raggedright{double precision} +& +\raggedright{double precision} +& +\raggedright{func} \tabularnewline +\raggedright{pg\_catalog} +& +\raggedright{exp} +& +\raggedright{numeric} +& +\raggedright{numeric} +& +\raggedright{func} \tabularnewline +\end{longtable} +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq +\begin{center} +Sequence "public.psql\_serial\_tab\_id\_seq" +\end{center} + +\begin{tabular}{c|l} +\multicolumn{2}{c}{\textit{Record 1}} \\ +\hline +Type & integer \\ +Start & 1 \\ +Minimum & 1 \\ +Maximum & 2147483647 \\ +Increment & 1 \\ +Cycles? & no \\ +Cache & 1 \\ +\end{tabular} + +\noindent Owned by: public.psql\_serial\_tab.id \\ + +\pset tuples_only true +\df exp +\begin{tabular}{c|l} +\hline +Schema & pg\_catalog \\ +Name & exp \\ +Result data type & double precision \\ +Argument data types & double precision \\ +Type & func \\ +\hline +Schema & pg\_catalog \\ +Name & exp \\ +Result data type & numeric \\ +Argument data types & numeric \\ +Type & func \\ +\end{tabular} + +\noindent +\pset tuples_only false +prepare q as + select 'some\more_text' as "a$title", E' #%&^~|\n{bar}' as "junk", + ' ' as "empty", n as int + from generate_series(1,2) as n; +\pset expanded off +\pset border 0 +execute q; +\begin{longtable}{lllr} +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endfirsthead +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endhead +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{1} \tabularnewline +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{2} \tabularnewline +\end{longtable} +\pset border 1 +execute q; +\begin{longtable}{l | l | l | r} +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endfirsthead +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endhead +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{1} \tabularnewline +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{2} \tabularnewline +\end{longtable} +\pset border 2 +execute q; +\begin{longtable}{| l | l | l | r |} +\toprule +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endfirsthead +\toprule +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endhead +\bottomrule +\endfoot +\bottomrule +\endlastfoot +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{1} \tabularnewline +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{2} \tabularnewline +\end{longtable} +\pset border 3 +execute q; +\begin{longtable}{| l | l | l | r |} +\toprule +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endfirsthead +\toprule +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\endhead +\bottomrule +\endfoot +\bottomrule +\endlastfoot +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{1} \tabularnewline + \hline +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{2} \tabularnewline + \hline +\end{longtable} +\pset tableattr lr +execute q; +\begin{longtable}{| p{lr\textwidth} | p{lr\textwidth} | p{lr\textwidth} | r |} +\toprule +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\midrule +\endfirsthead +\toprule +\small\textbf{\textit{a\$title}} & \small\textbf{\textit{junk}} & \small\textbf{\textit{empty}} & \small\textbf{\textit{int}} \\ +\endhead +\bottomrule +\endfoot +\bottomrule +\endlastfoot +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{1} \tabularnewline + \hline +\raggedright{some\textbackslash{}more\_text} +& +\raggedright{ \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\}} +& +\raggedright{ } +& +\raggedright{2} \tabularnewline + \hline +\end{longtable} +\pset tableattr +\pset expanded on +\pset border 0 +execute q; +\begin{tabular}{cl} +\multicolumn{2}{c}{\textit{Record 1}} \\ +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\multicolumn{2}{c}{\textit{Record 2}} \\ +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\end{tabular} + +\noindent +\pset border 1 +execute q; +\begin{tabular}{c|l} +\multicolumn{2}{c}{\textit{Record 1}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\multicolumn{2}{c}{\textit{Record 2}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\end{tabular} + +\noindent +\pset border 2 +execute q; +\begin{tabular}{|c|l|} +\hline +\multicolumn{2}{|c|}{\textit{Record 1}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\hline +\multicolumn{2}{|c|}{\textit{Record 2}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\hline +\end{tabular} + +\noindent +\pset border 3 +execute q; +\begin{tabular}{|c|l|} +\hline +\multicolumn{2}{|c|}{\textit{Record 1}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\hline +\multicolumn{2}{|c|}{\textit{Record 2}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\hline +\end{tabular} + +\noindent +\pset tableattr lr +execute q; +\begin{tabular}{|c|l|} +\hline +\multicolumn{2}{|c|}{\textit{Record 1}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 1 \\ +\hline +\multicolumn{2}{|c|}{\textit{Record 2}} \\ +\hline +a\$title & some\textbackslash{}more\_text \\ +junk & \#\textless{}foo\textgreater{}\%\&\^{}\~{}\textbar{}\\\{bar\} \\ +empty & \\ +int & 2 \\ +\hline +\end{tabular} + +\noindent +\pset tableattr +deallocate q; +-- test troff-ms output format +\pset format troff-ms +\pset border 1 +\pset expanded off +\d psql_serial_tab_id_seq +.LP +.DS C +Sequence "public.psql_serial_tab_id_seq" +.DE +.LP +.TS +center; +l | r | r | r | r | l | r. +\fIType\fP \fIStart\fP \fIMinimum\fP \fIMaximum\fP \fIIncrement\fP \fICycles?\fP \fICache\fP +_ +integer 1 1 2147483647 1 no 1 +.TE +.DS L +Owned by: public.psql_serial_tab.id +.DE +\pset tuples_only true +\df exp +.LP +.TS +center; +l | l | l | l | l. +pg_catalog exp double precision double precision func +pg_catalog exp numeric numeric func +.TE +.DS L +.DE +\pset tuples_only false +\pset expanded on +\d psql_serial_tab_id_seq +.LP +.DS C +Sequence "public.psql_serial_tab_id_seq" +.DE +.LP +.TS +center; +c s. +\fIRecord 1\fP +_ +.T& +c | l. +Type integer +Start 1 +Minimum 1 +Maximum 2147483647 +Increment 1 +Cycles? no +Cache 1 +.TE +.DS L +Owned by: public.psql_serial_tab.id +.DE +\pset tuples_only true +\df exp +.LP +.TS +center; +c l; +_ +Schema pg_catalog +Name exp +Result data type double precision +Argument data types double precision +Type func +_ +Schema pg_catalog +Name exp +Result data type numeric +Argument data types numeric +Type func +.TE +.DS L +.DE +\pset tuples_only false +prepare q as + select 'some\text' as "a\title", E' \n' as "junk", + ' ' as "empty", n as int + from generate_series(1,2) as n; +\pset expanded off +\pset border 0 +execute q; +.LP +.TS +center; +lllr. +\fIa\(rstitle\fP \fIjunk\fP \fIempty\fP \fIint\fP +_ +some\(rstext + 1 +some\(rstext + 2 +.TE +.DS L +(2 rows) +.DE +\pset border 1 +execute q; +.LP +.TS +center; +l | l | l | r. +\fIa\(rstitle\fP \fIjunk\fP \fIempty\fP \fIint\fP +_ +some\(rstext + 1 +some\(rstext + 2 +.TE +.DS L +(2 rows) +.DE +\pset border 2 +execute q; +.LP +.TS +center box; +l | l | l | r. +\fIa\(rstitle\fP \fIjunk\fP \fIempty\fP \fIint\fP +_ +some\(rstext + 1 +some\(rstext + 2 +.TE +.DS L +(2 rows) +.DE +\pset expanded on +\pset border 0 +execute q; +.LP +.TS +center; +c s. +\fIRecord 1\fP +.T& +c l. +a\(rstitle some\(rstext +junk + +empty +int 1 +.T& +c s. +\fIRecord 2\fP +.T& +c l. +a\(rstitle some\(rstext +junk + +empty +int 2 +.TE +.DS L +.DE +\pset border 1 +execute q; +.LP +.TS +center; +c s. +\fIRecord 1\fP +_ +.T& +c | l. +a\(rstitle some\(rstext +junk + +empty +int 1 +.T& +c s. +\fIRecord 2\fP +_ +.T& +c | l. +a\(rstitle some\(rstext +junk + +empty +int 2 +.TE +.DS L +.DE +\pset border 2 +execute q; +.LP +.TS +center box; +c s. +\fIRecord 1\fP +_ +.T& +c l. +a\(rstitle some\(rstext +junk + +empty +int 1 +_ +.T& +c s. +\fIRecord 2\fP +_ +.T& +c l. +a\(rstitle some\(rstext +junk + +empty +int 2 +.TE +.DS L +.DE +deallocate q; +-- check ambiguous format requests +\pset format a +\pset: ambiguous abbreviation "a" matches both "aligned" and "asciidoc" +\pset format l +-- clean up after output format tests +drop table psql_serial_tab; +\pset format aligned +\pset expanded off +\pset border 1 +-- \echo and allied features +\echo this is a test +this is a test +\echo -n without newline +without newline\echo with -n newline +with -n newline +\echo '-n' with newline +-n with newline +\set foo bar +\echo foo = :foo +foo = bar +\qecho this is a test +this is a test +\qecho foo = :foo +foo = bar +\warn this is a test +this is a test +\warn foo = :foo +foo = bar +-- tests for \if ... \endif +\if true + select 'okay'; + ?column? +---------- + okay +(1 row) + + select 'still okay'; + ?column? +------------ + still okay +(1 row) + +\else + not okay; + still not okay +\endif +-- at this point query buffer should still have last valid line +\g + ?column? +------------ + still okay +(1 row) + +-- \if should work okay on part of a query +select + \if true + 42 + \else + (bogus + \endif + forty_two; + forty_two +----------- + 42 +(1 row) + +select \if false \\ (bogus \else \\ 42 \endif \\ forty_two; + forty_two +----------- + 42 +(1 row) + +-- test a large nested if using a variety of true-equivalents +\if true + \if 1 + \if yes + \if on + \echo 'all true' +all true + \else + \echo 'should not print #1-1' + \endif + \else + \echo 'should not print #1-2' + \endif + \else + \echo 'should not print #1-3' + \endif +\else + \echo 'should not print #1-4' +\endif +-- test a variety of false-equivalents in an if/elif/else structure +\if false + \echo 'should not print #2-1' +\elif 0 + \echo 'should not print #2-2' +\elif no + \echo 'should not print #2-3' +\elif off + \echo 'should not print #2-4' +\else + \echo 'all false' +all false +\endif +-- test true-false elif after initial true branch +\if true + \echo 'should print #2-5' +should print #2-5 +\elif true + \echo 'should not print #2-6' +\elif false + \echo 'should not print #2-7' +\else + \echo 'should not print #2-8' +\endif +-- test simple true-then-else +\if true + \echo 'first thing true' +first thing true +\else + \echo 'should not print #3-1' +\endif +-- test simple false-true-else +\if false + \echo 'should not print #4-1' +\elif true + \echo 'second thing true' +second thing true +\else + \echo 'should not print #5-1' +\endif +-- invalid boolean expressions are false +\if invalid boolean expression +unrecognized value "invalid boolean expression" for "\if expression": Boolean expected + \echo 'will not print #6-1' +\else + \echo 'will print anyway #6-2' +will print anyway #6-2 +\endif +-- test un-matched endif +\endif +\endif: no matching \if +-- test un-matched else +\else +\else: no matching \if +-- test un-matched elif +\elif +\elif: no matching \if +-- test double-else error +\if true +\else +\else +\else: cannot occur after \else +\endif +-- test elif out-of-order +\if false +\else +\elif +\elif: cannot occur after \else +\endif +-- test if-endif matching in a false branch +\if false + \if false + \echo 'should not print #7-1' + \else + \echo 'should not print #7-2' + \endif + \echo 'should not print #7-3' +\else + \echo 'should print #7-4' +should print #7-4 +\endif +-- show that vars and backticks are not expanded when ignoring extra args +\set foo bar +\echo :foo :'foo' :"foo" +bar 'bar' "bar" +\pset fieldsep | `nosuchcommand` :foo :'foo' :"foo" +\pset: extra argument "nosuchcommand" ignored +\pset: extra argument ":foo" ignored +\pset: extra argument ":'foo'" ignored +\pset: extra argument ":"foo"" ignored +-- show that vars and backticks are not expanded and commands are ignored +-- when in a false if-branch +\set try_to_quit '\\q' +\if false + :try_to_quit + \echo `nosuchcommand` :foo :'foo' :"foo" + \pset fieldsep | `nosuchcommand` :foo :'foo' :"foo" + \a + SELECT $1 \bind 1 \g + \bind_named stmt1 1 2 \g + \C arg1 + \c arg1 arg2 arg3 arg4 + \cd arg1 + \close_prepared stmt1 + \conninfo + \copy arg1 arg2 arg3 arg4 arg5 arg6 + \copyright + SELECT 1 as one, 2, 3 \crosstabview + \dt arg1 + \e arg1 arg2 + \ef whole_line + \ev whole_line + \echo arg1 arg2 arg3 arg4 arg5 + \echo arg1 + \encoding arg1 + \endpipeline + \errverbose + \f arg1 + \flush + \flushrequest + \g arg1 + \gx arg1 + \gexec + \getresults + SELECT 1 AS one \gset + \h + \? + \html + \i arg1 + \ir arg1 + \l arg1 + \lo arg1 arg2 +invalid command \lo + \lo_list + \o arg1 + \p + SELECT 1 \parse + \password arg1 + \prompt arg1 arg2 + \pset arg1 arg2 + \q + \reset + \restrict test + \s arg1 + \sendpipeline + \set arg1 arg2 arg3 arg4 arg5 arg6 arg7 + \setenv arg1 arg2 + \sf whole_line + \sv whole_line + \startpipeline + \syncpipeline + \t arg1 + \T arg1 + \timing arg1 + \unrestrict not_valid + \unset arg1 + \w arg1 + \watch arg1 arg2 + \x arg1 + -- \else here is eaten as part of OT_FILEPIPE argument + \w |/no/such/file \else + -- \endif here is eaten as part of whole-line argument + \! whole_line \endif + \z +\else + \echo 'should print #8-1' +should print #8-1 +\endif +-- :{?...} defined variable test +\set i 1 +\if :{?i} + \echo '#9-1 ok, variable i is defined' +#9-1 ok, variable i is defined +\else + \echo 'should not print #9-2' +\endif +\if :{?no_such_variable} + \echo 'should not print #10-1' +\else + \echo '#10-2 ok, variable no_such_variable is not defined' +#10-2 ok, variable no_such_variable is not defined +\endif +SELECT :{?i} AS i_is_defined; + i_is_defined +-------------- + t +(1 row) + +SELECT NOT :{?no_such_var} AS no_such_var_is_not_defined; + no_such_var_is_not_defined +---------------------------- + t +(1 row) + +-- SHOW_CONTEXT +\set SHOW_CONTEXT never +do $$ +begin + raise notice 'foo'; + raise exception 'bar'; +end $$; +NOTICE: foo +ERROR: bar +\set SHOW_CONTEXT errors +do $$ +begin + raise notice 'foo'; + raise exception 'bar'; +end $$; +NOTICE: foo +ERROR: bar +CONTEXT: PL/pgSQL function inline_code_block line 4 at RAISE +\set SHOW_CONTEXT always +do $$ +begin + raise notice 'foo'; + raise exception 'bar'; +end $$; +NOTICE: foo +CONTEXT: PL/pgSQL function inline_code_block line 3 at RAISE +ERROR: bar +CONTEXT: PL/pgSQL function inline_code_block line 4 at RAISE +-- test printing and clearing the query buffer +SELECT 1; + ?column? +---------- + 1 +(1 row) + +\p +SELECT 1; +SELECT 2 \r +\p +SELECT 1; +SELECT 3 \p +SELECT 3 +UNION SELECT 4 \p +SELECT 3 +UNION SELECT 4 +UNION SELECT 5 +ORDER BY 1; + ?column? +---------- + 3 + 4 + 5 +(3 rows) + +\r +\p +SELECT 3 +UNION SELECT 4 +UNION SELECT 5 +ORDER BY 1; +-- tests for special result variables +-- working query, 2 rows selected +SELECT 1 AS stuff UNION SELECT 2; + stuff +------- + 1 + 2 +(2 rows) + +\echo 'error:' :ERROR +error: false +\echo 'error code:' :SQLSTATE +error code: 00000 +\echo 'number of rows:' :ROW_COUNT +number of rows: 2 +-- syntax error +SELECT 1 UNION; +ERROR: syntax error at or near ";" +LINE 1: SELECT 1 UNION; + ^ +\echo 'error:' :ERROR +error: true +\echo 'error code:' :SQLSTATE +error code: 42601 +\echo 'number of rows:' :ROW_COUNT +number of rows: 0 +\echo 'last error message:' :LAST_ERROR_MESSAGE +last error message: syntax error at or near ";" +\echo 'last error code:' :LAST_ERROR_SQLSTATE +last error code: 42601 +-- empty query +; +\echo 'error:' :ERROR +error: false +\echo 'error code:' :SQLSTATE +error code: 00000 +\echo 'number of rows:' :ROW_COUNT +number of rows: 0 +-- must have kept previous values +\echo 'last error message:' :LAST_ERROR_MESSAGE +last error message: syntax error at or near ";" +\echo 'last error code:' :LAST_ERROR_SQLSTATE +last error code: 42601 +-- other query error +DROP TABLE this_table_does_not_exist; +ERROR: table "this_table_does_not_exist" does not exist +\echo 'error:' :ERROR +error: true +\echo 'error code:' :SQLSTATE +error code: 42P01 +\echo 'number of rows:' :ROW_COUNT +number of rows: 0 +\echo 'last error message:' :LAST_ERROR_MESSAGE +last error message: table "this_table_does_not_exist" does not exist +\echo 'last error code:' :LAST_ERROR_SQLSTATE +last error code: 42P01 +-- nondefault verbosity error settings (except verbose, which is too unstable) +\set VERBOSITY terse +SELECT 1 UNION; +ERROR: syntax error at or near ";" at character 15 +\echo 'error:' :ERROR +error: true +\echo 'error code:' :SQLSTATE +error code: 42601 +\echo 'last error message:' :LAST_ERROR_MESSAGE +last error message: syntax error at or near ";" +\set VERBOSITY sqlstate +SELECT 1/0; +ERROR: 22012 +\echo 'error:' :ERROR +error: true +\echo 'error code:' :SQLSTATE +error code: 22012 +\echo 'last error message:' :LAST_ERROR_MESSAGE +last error message: division by zero +\set VERBOSITY default +-- working \gdesc +SELECT 3 AS three, 4 AS four \gdesc + Column | Type +--------+--------- + three | integer + four | integer +(2 rows) + +\echo 'error:' :ERROR +error: false +\echo 'error code:' :SQLSTATE +error code: 00000 +\echo 'number of rows:' :ROW_COUNT +number of rows: 2 +-- \gdesc with an error +SELECT 4 AS \gdesc +ERROR: syntax error at end of input +LINE 1: SELECT 4 AS + ^ +\echo 'error:' :ERROR +error: true +\echo 'error code:' :SQLSTATE +error code: 42601 +\echo 'number of rows:' :ROW_COUNT +number of rows: 0 +\echo 'last error message:' :LAST_ERROR_MESSAGE +last error message: syntax error at end of input +\echo 'last error code:' :LAST_ERROR_SQLSTATE +last error code: 42601 +-- check row count for a query with chunked results +\set FETCH_COUNT 10 +select unique2 from tenk1 order by unique2 limit 19; + unique2 +--------- + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 +(19 rows) + +\echo 'error:' :ERROR +error: false +\echo 'error code:' :SQLSTATE +error code: 00000 +\echo 'number of rows:' :ROW_COUNT +number of rows: 19 +-- chunked results with an error after the first chunk +-- (we must disable parallel query here, else the behavior is timing-dependent) +set debug_parallel_query = off; +select 1/(15-unique2) from tenk1 order by unique2 limit 19; + ?column? +---------- + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +ERROR: division by zero +\echo 'error:' :ERROR +error: true +\echo 'error code:' :SQLSTATE +error code: 22012 +\echo 'number of rows:' :ROW_COUNT +number of rows: 0 +\echo 'last error message:' :LAST_ERROR_MESSAGE +last error message: division by zero +\echo 'last error code:' :LAST_ERROR_SQLSTATE +last error code: 22012 +reset debug_parallel_query; +\unset FETCH_COUNT +create schema testpart; +create role regress_partitioning_role; +alter schema testpart owner to regress_partitioning_role; +set role to regress_partitioning_role; +-- run test inside own schema and hide other partitions +set search_path to testpart; +create table testtable_apple(logdate date); +create table testtable_orange(logdate date); +create index testtable_apple_index on testtable_apple(logdate); +create index testtable_orange_index on testtable_orange(logdate); +create table testpart_apple(logdate date) partition by range(logdate); +create table testpart_orange(logdate date) partition by range(logdate); +create index testpart_apple_index on testpart_apple(logdate); +create index testpart_orange_index on testpart_orange(logdate); +-- only partition related object should be displayed +\dP test*apple* + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +----------+----------------------+---------------------------+-------------------+-------------+---------------- + testpart | testpart_apple | regress_partitioning_role | partitioned table | | + testpart | testpart_apple_index | regress_partitioning_role | partitioned index | | testpart_apple +(2 rows) + +\dPt test*apple* + List of partitioned tables + Schema | Name | Owner | Parent name +----------+----------------+---------------------------+------------- + testpart | testpart_apple | regress_partitioning_role | +(1 row) + +\dPi test*apple* + List of partitioned indexes + Schema | Name | Owner | Parent name | Table +----------+----------------------+---------------------------+-------------+---------------- + testpart | testpart_apple_index | regress_partitioning_role | | testpart_apple +(1 row) + +drop table testtable_apple; +drop table testtable_orange; +drop table testpart_apple; +drop table testpart_orange; +create table parent_tab (id int) partition by range (id); +create index parent_index on parent_tab (id); +create table child_0_10 partition of parent_tab + for values from (0) to (10); +create table child_10_20 partition of parent_tab + for values from (10) to (20); +create table child_20_30 partition of parent_tab + for values from (20) to (30); +insert into parent_tab values (generate_series(0,29)); +create table child_30_40 partition of parent_tab +for values from (30) to (40) + partition by range(id); +create table child_30_35 partition of child_30_40 + for values from (30) to (35); +create table child_35_40 partition of child_30_40 + for values from (35) to (40); +insert into parent_tab values (generate_series(30,39)); +\dPt + List of partitioned tables + Schema | Name | Owner +----------+------------+--------------------------- + testpart | parent_tab | regress_partitioning_role +(1 row) + +\dPi + List of partitioned indexes + Schema | Name | Owner | Table +----------+--------------+---------------------------+------------ + testpart | parent_index | regress_partitioning_role | parent_tab +(1 row) + +\dP testpart.* + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +----------+--------------------+---------------------------+-------------------+--------------+------------- + testpart | parent_tab | regress_partitioning_role | partitioned table | | + testpart | child_30_40 | regress_partitioning_role | partitioned table | parent_tab | + testpart | parent_index | regress_partitioning_role | partitioned index | | parent_tab + testpart | child_30_40_id_idx | regress_partitioning_role | partitioned index | parent_index | child_30_40 +(4 rows) + +\dP + List of partitioned relations + Schema | Name | Owner | Type | Table +----------+--------------+---------------------------+-------------------+------------ + testpart | parent_tab | regress_partitioning_role | partitioned table | + testpart | parent_index | regress_partitioning_role | partitioned index | parent_tab +(2 rows) + +\dPtn + List of partitioned tables + Schema | Name | Owner | Parent name +----------+-------------+---------------------------+------------- + testpart | parent_tab | regress_partitioning_role | + testpart | child_30_40 | regress_partitioning_role | parent_tab +(2 rows) + +\dPin + List of partitioned indexes + Schema | Name | Owner | Parent name | Table +----------+--------------------+---------------------------+--------------+------------- + testpart | parent_index | regress_partitioning_role | | parent_tab + testpart | child_30_40_id_idx | regress_partitioning_role | parent_index | child_30_40 +(2 rows) + +\dPn + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +----------+--------------------+---------------------------+-------------------+--------------+------------- + testpart | parent_tab | regress_partitioning_role | partitioned table | | + testpart | child_30_40 | regress_partitioning_role | partitioned table | parent_tab | + testpart | parent_index | regress_partitioning_role | partitioned index | | parent_tab + testpart | child_30_40_id_idx | regress_partitioning_role | partitioned index | parent_index | child_30_40 +(4 rows) + +\dPn testpart.* + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +----------+--------------------+---------------------------+-------------------+--------------+------------- + testpart | parent_tab | regress_partitioning_role | partitioned table | | + testpart | child_30_40 | regress_partitioning_role | partitioned table | parent_tab | + testpart | parent_index | regress_partitioning_role | partitioned index | | parent_tab + testpart | child_30_40_id_idx | regress_partitioning_role | partitioned index | parent_index | child_30_40 +(4 rows) + +drop table parent_tab cascade; +drop schema testpart; +set search_path to default; +set role to default; +drop role regress_partitioning_role; +-- \d on toast table (use pg_statistic's toast table, which has a known name) +\d pg_toast.pg_toast_2619 +TOAST table "pg_toast.pg_toast_2619" + Column | Type +------------+--------- + chunk_id | oid + chunk_seq | integer + chunk_data | bytea +Owning table: "pg_catalog.pg_statistic" +Indexes: + "pg_toast_2619_index" PRIMARY KEY, btree (chunk_id, chunk_seq) + +-- check printing info about access methods +\dA +List of access methods + Name | Type +----------+------- + brin | Index + btree | Index + gin | Index + gist | Index + hash | Index + heap | Table + heap2 | Table + spgist | Index + tde_heap | Table +(9 rows) + +\dA * +List of access methods + Name | Type +----------+------- + brin | Index + btree | Index + gin | Index + gist | Index + hash | Index + heap | Table + heap2 | Table + spgist | Index + tde_heap | Table +(9 rows) + +\dA h* +List of access methods + Name | Type +-------+------- + hash | Index + heap | Table + heap2 | Table +(3 rows) + +\dA foo +List of access methods + Name | Type +------+------ +(0 rows) + +\dA foo bar +List of access methods + Name | Type +------+------ +(0 rows) + +\dA: extra argument "bar" ignored +\dA+ + List of access methods + Name | Type | Handler | Description +----------+-------+--------------------------+---------------------------------------- + brin | Index | brinhandler | block range index (BRIN) access method + btree | Index | bthandler | b-tree index access method + gin | Index | ginhandler | GIN index access method + gist | Index | gisthandler | GiST index access method + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | + spgist | Index | spghandler | SP-GiST index access method + tde_heap | Table | _pg_tde.pg_tdeam_handler | tde_heap table access method +(9 rows) + +\dA+ * + List of access methods + Name | Type | Handler | Description +----------+-------+--------------------------+---------------------------------------- + brin | Index | brinhandler | block range index (BRIN) access method + btree | Index | bthandler | b-tree index access method + gin | Index | ginhandler | GIN index access method + gist | Index | gisthandler | GiST index access method + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | + spgist | Index | spghandler | SP-GiST index access method + tde_heap | Table | _pg_tde.pg_tdeam_handler | tde_heap table access method +(9 rows) + +\dA+ h* + List of access methods + Name | Type | Handler | Description +-------+-------+----------------------+-------------------------- + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | +(3 rows) + +\dA+ foo + List of access methods + Name | Type | Handler | Description +------+------+---------+------------- +(0 rows) + +\dAc brin pg*.oid* + List of operator classes + AM | Input type | Storage type | Operator class | Default? +------+------------+--------------+----------------------+---------- + brin | oid | | oid_bloom_ops | no + brin | oid | | oid_minmax_multi_ops | no + brin | oid | | oid_minmax_ops | yes +(3 rows) + +\dAf spgist + List of operator families + AM | Operator family | Applicable types +--------+-----------------+------------------ + spgist | box_ops | box + spgist | kd_point_ops | point + spgist | network_ops | inet + spgist | poly_ops | polygon + spgist | quad_point_ops | point + spgist | range_ops | anyrange + spgist | text_ops | text +(7 rows) + +\dAf btree int4 + List of operator families + AM | Operator family | Applicable types +-------+-----------------+--------------------------- + btree | integer_ops | smallint, integer, bigint +(1 row) + +\dAo+ btree array_ops|float_ops + List of operators of operator families + AM | Operator family | Operator | Strategy | Purpose | Sort opfamily | Leakproof? +-------+-----------------+---------------------------------------+----------+---------+---------------+------------ + btree | array_ops | <(anyarray,anyarray) | 1 | search | | no + btree | array_ops | <=(anyarray,anyarray) | 2 | search | | no + btree | array_ops | =(anyarray,anyarray) | 3 | search | | no + btree | array_ops | >=(anyarray,anyarray) | 4 | search | | no + btree | array_ops | >(anyarray,anyarray) | 5 | search | | no + btree | float_ops | <(double precision,double precision) | 1 | search | | yes + btree | float_ops | <=(double precision,double precision) | 2 | search | | yes + btree | float_ops | =(double precision,double precision) | 3 | search | | yes + btree | float_ops | >=(double precision,double precision) | 4 | search | | yes + btree | float_ops | >(double precision,double precision) | 5 | search | | yes + btree | float_ops | <(real,real) | 1 | search | | yes + btree | float_ops | <=(real,real) | 2 | search | | yes + btree | float_ops | =(real,real) | 3 | search | | yes + btree | float_ops | >=(real,real) | 4 | search | | yes + btree | float_ops | >(real,real) | 5 | search | | yes + btree | float_ops | <(double precision,real) | 1 | search | | yes + btree | float_ops | <=(double precision,real) | 2 | search | | yes + btree | float_ops | =(double precision,real) | 3 | search | | yes + btree | float_ops | >=(double precision,real) | 4 | search | | yes + btree | float_ops | >(double precision,real) | 5 | search | | yes + btree | float_ops | <(real,double precision) | 1 | search | | yes + btree | float_ops | <=(real,double precision) | 2 | search | | yes + btree | float_ops | =(real,double precision) | 3 | search | | yes + btree | float_ops | >=(real,double precision) | 4 | search | | yes + btree | float_ops | >(real,double precision) | 5 | search | | yes +(25 rows) + +\dAo * pg_catalog.jsonb_path_ops + List of operators of operator families + AM | Operator family | Operator | Strategy | Purpose +-----+-----------------+--------------------+----------+--------- + gin | jsonb_path_ops | @>(jsonb,jsonb) | 7 | search + gin | jsonb_path_ops | @?(jsonb,jsonpath) | 15 | search + gin | jsonb_path_ops | @@(jsonb,jsonpath) | 16 | search +(3 rows) + +\dAp+ btree float_ops + List of support functions of operator families + AM | Operator family | Registered left type | Registered right type | Number | Function +-------+-----------------+----------------------+-----------------------+--------+------------------------------------------------------------------------------ + btree | float_ops | double precision | double precision | 1 | btfloat8cmp(double precision,double precision) + btree | float_ops | double precision | double precision | 2 | btfloat8sortsupport(internal) + btree | float_ops | double precision | double precision | 3 | in_range(double precision,double precision,double precision,boolean,boolean) + btree | float_ops | real | real | 1 | btfloat4cmp(real,real) + btree | float_ops | real | real | 2 | btfloat4sortsupport(internal) + btree | float_ops | double precision | real | 1 | btfloat84cmp(double precision,real) + btree | float_ops | real | double precision | 1 | btfloat48cmp(real,double precision) + btree | float_ops | real | double precision | 3 | in_range(real,real,double precision,boolean,boolean) +(8 rows) + +\dApx+ btree time_ops +List of support functions of operator families +-[ RECORD 1 ]---------+--------------------------------------------------------------------------------- +AM | btree +Operator family | time_ops +Registered left type | time without time zone +Registered right type | time without time zone +Number | 1 +Function | time_cmp(time without time zone,time without time zone) +-[ RECORD 2 ]---------+--------------------------------------------------------------------------------- +AM | btree +Operator family | time_ops +Registered left type | time without time zone +Registered right type | time without time zone +Number | 4 +Function | btequalimage(oid) +-[ RECORD 3 ]---------+--------------------------------------------------------------------------------- +AM | btree +Operator family | time_ops +Registered left type | time without time zone +Registered right type | interval +Number | 3 +Function | in_range(time without time zone,time without time zone,interval,boolean,boolean) + +\dAp * pg_catalog.uuid_ops + List of support functions of operator families + AM | Operator family | Registered left type | Registered right type | Number | Function +-------+-----------------+----------------------+-----------------------+--------+-------------------- + btree | uuid_ops | uuid | uuid | 1 | uuid_cmp + btree | uuid_ops | uuid | uuid | 2 | uuid_sortsupport + btree | uuid_ops | uuid | uuid | 4 | btequalimage + btree | uuid_ops | uuid | uuid | 6 | uuid_skipsupport + hash | uuid_ops | uuid | uuid | 1 | uuid_hash + hash | uuid_ops | uuid | uuid | 2 | uuid_hash_extended +(6 rows) + +-- check \dconfig +set work_mem = 10240; +\dconfig work_mem +List of configuration parameters + Parameter | Value +-----------+------- + work_mem | 10MB +(1 row) + +\dconfig+ work* + List of configuration parameters + Parameter | Value | Type | Context | Access privileges +-----------+-------+---------+---------+------------------- + work_mem | 10MB | integer | user | +(1 row) + +reset work_mem; +-- check \df, \do with argument specifications +\df *sqrt + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+--------------+------------------+---------------------+------ + pg_catalog | dsqrt | double precision | double precision | func + pg_catalog | numeric_sqrt | numeric | numeric | func + pg_catalog | sqrt | double precision | double precision | func + pg_catalog | sqrt | numeric | numeric | func +(4 rows) + +\df *sqrt num* + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+--------------+------------------+---------------------+------ + pg_catalog | numeric_sqrt | numeric | numeric | func + pg_catalog | sqrt | numeric | numeric | func +(2 rows) + +\df int*pl + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+-------------+------------------+---------------------+------ + pg_catalog | int24pl | integer | smallint, integer | func + pg_catalog | int28pl | bigint | smallint, bigint | func + pg_catalog | int2pl | smallint | smallint, smallint | func + pg_catalog | int42pl | integer | integer, smallint | func + pg_catalog | int48pl | bigint | integer, bigint | func + pg_catalog | int4pl | integer | integer, integer | func + pg_catalog | int82pl | bigint | bigint, smallint | func + pg_catalog | int84pl | bigint | bigint, integer | func + pg_catalog | int8pl | bigint | bigint, bigint | func + pg_catalog | interval_pl | interval | interval, interval | func +(10 rows) + +\df int*pl int4 + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+---------+------------------+---------------------+------ + pg_catalog | int42pl | integer | integer, smallint | func + pg_catalog | int48pl | bigint | integer, bigint | func + pg_catalog | int4pl | integer | integer, integer | func +(3 rows) + +\df int*pl * pg_catalog.int8 + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+---------+------------------+---------------------+------ + pg_catalog | int28pl | bigint | smallint, bigint | func + pg_catalog | int48pl | bigint | integer, bigint | func + pg_catalog | int8pl | bigint | bigint, bigint | func +(3 rows) + +\df acl* aclitem[] + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+-------------+------------------+----------------------------------------------------------------------------------------------------+------ + pg_catalog | aclcontains | boolean | aclitem[], aclitem | func + pg_catalog | aclexplode | SETOF record | acl aclitem[], OUT grantor oid, OUT grantee oid, OUT privilege_type text, OUT is_grantable boolean | func + pg_catalog | aclinsert | aclitem[] | aclitem[], aclitem | func + pg_catalog | aclremove | aclitem[] | aclitem[], aclitem | func +(4 rows) + +\df has_database_privilege oid text + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+------------------------+------------------+---------------------+------ + pg_catalog | has_database_privilege | boolean | oid, text | func + pg_catalog | has_database_privilege | boolean | oid, text, text | func +(2 rows) + +\df has_database_privilege oid text - + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+------------------------+------------------+---------------------+------ + pg_catalog | has_database_privilege | boolean | oid, text | func +(1 row) + +\dfa bit* small* + List of functions + Schema | Name | Result data type | Argument data types | Type +------------+---------+------------------+---------------------+------ + pg_catalog | bit_and | smallint | smallint | agg + pg_catalog | bit_or | smallint | smallint | agg + pg_catalog | bit_xor | smallint | smallint | agg +(3 rows) + +\df *._pg_expandarray + List of functions + Schema | Name | Result data type | Argument data types | Type +--------------------+-----------------+------------------+-------------------------------------------+------ + information_schema | _pg_expandarray | SETOF record | anyarray, OUT x anyelement, OUT n integer | func +(1 row) + +\do - pg_catalog.int4 + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +------------+------+---------------+----------------+-------------+------------- + pg_catalog | - | | integer | integer | negate +(1 row) + +\do && anyarray * + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +------------+------+---------------+----------------+-------------+------------- + pg_catalog | && | anyarray | anyarray | boolean | overlaps +(1 row) + +-- check \df+ +-- we have to use functions with a predictable owner name, so make a role +create role regress_psql_user superuser; +begin; +set session authorization regress_psql_user; +create function psql_df_internal (float8) + returns float8 + language internal immutable parallel safe strict + as 'dsin'; +create function psql_df_sql (x integer) + returns integer + security definer + begin atomic select x + 1; end; +create function psql_df_plpgsql () + returns void + language plpgsql + as $$ begin return; end; $$; +comment on function psql_df_plpgsql () is 'some comment'; +\df+ psql_df_* + List of functions + Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Leakproof? | Access privileges | Language | Internal name | Description +--------+------------------+------------------+---------------------+------+------------+----------+-------------------+----------+------------+-------------------+----------+---------------+-------------- + public | psql_df_internal | double precision | double precision | func | immutable | safe | regress_psql_user | invoker | no | | internal | dsin | + public | psql_df_plpgsql | void | | func | volatile | unsafe | regress_psql_user | invoker | no | | plpgsql | | some comment + public | psql_df_sql | integer | x integer | func | volatile | unsafe | regress_psql_user | definer | no | | sql | | +(3 rows) + +rollback; +drop role regress_psql_user; +-- check \sf +\sf information_schema._pg_index_position +CREATE OR REPLACE FUNCTION information_schema._pg_index_position(oid, smallint) + RETURNS integer + LANGUAGE sql + STABLE STRICT +BEGIN ATOMIC + SELECT (ss.a).n AS n + FROM ( SELECT information_schema._pg_expandarray(pg_index.indkey) AS a + FROM pg_index + WHERE (pg_index.indexrelid = $1)) ss + WHERE ((ss.a).x = $2); +END +\sf+ information_schema._pg_index_position + CREATE OR REPLACE FUNCTION information_schema._pg_index_position(oid, smallint) + RETURNS integer + LANGUAGE sql + STABLE STRICT +1 BEGIN ATOMIC +2 SELECT (ss.a).n AS n +3 FROM ( SELECT information_schema._pg_expandarray(pg_index.indkey) AS a +4 FROM pg_index +5 WHERE (pg_index.indexrelid = $1)) ss +6 WHERE ((ss.a).x = $2); +7 END +\sf+ interval_pl_time + CREATE OR REPLACE FUNCTION pg_catalog.interval_pl_time(interval, time without time zone) + RETURNS time without time zone + LANGUAGE sql + IMMUTABLE PARALLEL SAFE STRICT COST 1 +1 RETURN ($2 + $1) +\sf ts_debug(text); +CREATE OR REPLACE FUNCTION pg_catalog.ts_debug(document text, OUT alias text, OUT description text, OUT token text, OUT dictionaries regdictionary[], OUT dictionary regdictionary, OUT lexemes text[]) + RETURNS SETOF record + LANGUAGE sql + STABLE PARALLEL SAFE STRICT +BEGIN ATOMIC + SELECT ts_debug.alias, + ts_debug.description, + ts_debug.token, + ts_debug.dictionaries, + ts_debug.dictionary, + ts_debug.lexemes + FROM ts_debug(get_current_ts_config(), ts_debug.document) ts_debug(alias, description, token, dictionaries, dictionary, lexemes); +END +\sf+ ts_debug(text) + CREATE OR REPLACE FUNCTION pg_catalog.ts_debug(document text, OUT alias text, OUT description text, OUT token text, OUT dictionaries regdictionary[], OUT dictionary regdictionary, OUT lexemes text[]) + RETURNS SETOF record + LANGUAGE sql + STABLE PARALLEL SAFE STRICT +1 BEGIN ATOMIC +2 SELECT ts_debug.alias, +3 ts_debug.description, +4 ts_debug.token, +5 ts_debug.dictionaries, +6 ts_debug.dictionary, +7 ts_debug.lexemes +8 FROM ts_debug(get_current_ts_config(), ts_debug.document) ts_debug(alias, description, token, dictionaries, dictionary, lexemes); +9 END +-- AUTOCOMMIT +CREATE TABLE ac_test (a int); +\set AUTOCOMMIT off +INSERT INTO ac_test VALUES (1); +COMMIT; +SELECT * FROM ac_test; + a +--- + 1 +(1 row) + +COMMIT; +INSERT INTO ac_test VALUES (2); +ROLLBACK; +SELECT * FROM ac_test; + a +--- + 1 +(1 row) + +COMMIT; +BEGIN; +INSERT INTO ac_test VALUES (3); +COMMIT; +SELECT * FROM ac_test; + a +--- + 1 + 3 +(2 rows) + +COMMIT; +BEGIN; +INSERT INTO ac_test VALUES (4); +ROLLBACK; +SELECT * FROM ac_test; + a +--- + 1 + 3 +(2 rows) + +COMMIT; +\set AUTOCOMMIT on +DROP TABLE ac_test; +SELECT * FROM ac_test; -- should be gone now +ERROR: relation "ac_test" does not exist +LINE 1: SELECT * FROM ac_test; + ^ +-- ON_ERROR_ROLLBACK +\set ON_ERROR_ROLLBACK on +CREATE TABLE oer_test (a int); +BEGIN; +INSERT INTO oer_test VALUES (1); +INSERT INTO oer_test VALUES ('foo'); +ERROR: invalid input syntax for type integer: "foo" +LINE 1: INSERT INTO oer_test VALUES ('foo'); + ^ +INSERT INTO oer_test VALUES (3); +COMMIT; +SELECT * FROM oer_test; + a +--- + 1 + 3 +(2 rows) + +BEGIN; +INSERT INTO oer_test VALUES (4); +ROLLBACK; +SELECT * FROM oer_test; + a +--- + 1 + 3 +(2 rows) + +BEGIN; +INSERT INTO oer_test VALUES (5); +COMMIT AND CHAIN; +INSERT INTO oer_test VALUES (6); +COMMIT; +SELECT * FROM oer_test; + a +--- + 1 + 3 + 5 + 6 +(4 rows) + +DROP TABLE oer_test; +\set ON_ERROR_ROLLBACK off +-- ECHO errors +\set ECHO errors +ERROR: relation "notexists" does not exist +LINE 1: SELECT * FROM notexists; + ^ +STATEMENT: SELECT * FROM notexists; +-- +-- combined queries +-- +CREATE FUNCTION warn(msg TEXT) RETURNS BOOLEAN LANGUAGE plpgsql +AS $$ + BEGIN RAISE NOTICE 'warn %', msg ; RETURN TRUE ; END +$$; +-- show both +SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ; +NOTICE: warn 1.5 +CONTEXT: PL/pgSQL function warn(text) line 2 at RAISE + one +----- + 1 +(1 row) + + warn +------ + t +(1 row) + + two +----- + 2 +(1 row) + +-- \gset applies to last query only +SELECT 3 AS three \; SELECT warn('3.5') \; SELECT 4 AS four \gset +NOTICE: warn 3.5 +CONTEXT: PL/pgSQL function warn(text) line 2 at RAISE + three +------- + 3 +(1 row) + + warn +------ + t +(1 row) + +\echo :three :four +:three 4 +-- syntax error stops all processing +SELECT 5 \; SELECT 6 + \; SELECT warn('6.5') \; SELECT 7 ; +ERROR: syntax error at or near ";" +LINE 1: SELECT 5 ; SELECT 6 + ; SELECT warn('6.5') ; SELECT 7 ; + ^ +-- with aborted transaction, stop on first error +BEGIN \; SELECT 8 AS eight \; SELECT 9/0 AS nine \; ROLLBACK \; SELECT 10 AS ten ; + eight +------- + 8 +(1 row) + +ERROR: division by zero +-- close previously aborted transaction +ROLLBACK; +-- miscellaneous SQL commands +-- (non SELECT output is sent to stderr, thus is not shown in expected results) +SELECT 'ok' AS "begin" \; +CREATE TABLE psql_comics(s TEXT) \; +INSERT INTO psql_comics VALUES ('Calvin'), ('hobbes') \; +COPY psql_comics FROM STDIN \; +UPDATE psql_comics SET s = 'Hobbes' WHERE s = 'hobbes' \; +DELETE FROM psql_comics WHERE s = 'Moe' \; +COPY psql_comics TO STDOUT \; +TRUNCATE psql_comics \; +DROP TABLE psql_comics \; +SELECT 'ok' AS "done" ; + begin +------- + ok +(1 row) + +Calvin +Susie +Hobbes + done +------ + ok +(1 row) + +\set SHOW_ALL_RESULTS off +SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ; +NOTICE: warn 1.5 +CONTEXT: PL/pgSQL function warn(text) line 2 at RAISE + two +----- + 2 +(1 row) + +\set SHOW_ALL_RESULTS on +DROP FUNCTION warn(TEXT); +-- +-- \g with file +-- +\getenv abs_builddir PG_ABS_BUILDDIR +\set g_out_file :abs_builddir '/results/psql-output1' +CREATE TEMPORARY TABLE reload_output( + lineno int NOT NULL GENERATED ALWAYS AS IDENTITY, + line text +); +SELECT 1 AS a \g :g_out_file +COPY reload_output(line) FROM :'g_out_file'; +SELECT 2 AS b\; SELECT 3 AS c\; SELECT 4 AS d \g :g_out_file +COPY reload_output(line) FROM :'g_out_file'; +COPY (SELECT 'foo') TO STDOUT \; COPY (SELECT 'bar') TO STDOUT \g :g_out_file +COPY reload_output(line) FROM :'g_out_file'; +SELECT line FROM reload_output ORDER BY lineno; + line +--------- + a + --- + 1 + (1 row) + + b + --- + 2 + (1 row) + + c + --- + 3 + (1 row) + + d + --- + 4 + (1 row) + + foo + bar +(22 rows) + +TRUNCATE TABLE reload_output; +-- +-- \o with file +-- +\set o_out_file :abs_builddir '/results/psql-output2' +\o :o_out_file +SELECT max(unique1) FROM onek; +SELECT 1 AS a\; SELECT 2 AS b\; SELECT 3 AS c; +-- COPY TO file +-- The data goes to :g_out_file and the status to :o_out_file +\set QUIET false +COPY (SELECT unique1 FROM onek ORDER BY unique1 LIMIT 10) TO :'g_out_file'; +-- DML command status +UPDATE onek SET unique1 = unique1 WHERE false; +\set QUIET true +\o +-- Check the contents of the files generated. +COPY reload_output(line) FROM :'g_out_file'; +SELECT line FROM reload_output ORDER BY lineno; + line +------ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +(10 rows) + +TRUNCATE TABLE reload_output; +COPY reload_output(line) FROM :'o_out_file'; +SELECT line FROM reload_output ORDER BY lineno; + line +---------- + max + ----- + 999 + (1 row) + + a + --- + 1 + (1 row) + + b + --- + 2 + (1 row) + + c + --- + 3 + (1 row) + + COPY 10 + UPDATE 0 +(22 rows) + +TRUNCATE TABLE reload_output; +-- Multiple COPY TO STDOUT with output file +\o :o_out_file +-- The data goes to :o_out_file with no status generated. +COPY (SELECT 'foo1') TO STDOUT \; COPY (SELECT 'bar1') TO STDOUT; +-- Combination of \o and \g file with multiple COPY queries. +COPY (SELECT 'foo2') TO STDOUT \; COPY (SELECT 'bar2') TO STDOUT \g :g_out_file +\o +-- Check the contents of the files generated. +COPY reload_output(line) FROM :'g_out_file'; +SELECT line FROM reload_output ORDER BY lineno; + line +------ + foo2 + bar2 +(2 rows) + +TRUNCATE TABLE reload_output; +COPY reload_output(line) FROM :'o_out_file'; +SELECT line FROM reload_output ORDER BY lineno; + line +------ + foo1 + bar1 +(2 rows) + +DROP TABLE reload_output; +-- +-- AUTOCOMMIT and combined queries +-- +\set AUTOCOMMIT off +\echo '# AUTOCOMMIT:' :AUTOCOMMIT +# AUTOCOMMIT: off +-- BEGIN is now implicit +CREATE TABLE foo(s TEXT) \; +ROLLBACK; +CREATE TABLE foo(s TEXT) \; +INSERT INTO foo(s) VALUES ('hello'), ('world') \; +COMMIT; +DROP TABLE foo \; +ROLLBACK; +-- table foo is still there +SELECT * FROM foo ORDER BY 1 \; +DROP TABLE foo \; +COMMIT; + s +------- + hello + world +(2 rows) + +\set AUTOCOMMIT on +\echo '# AUTOCOMMIT:' :AUTOCOMMIT +# AUTOCOMMIT: on +-- BEGIN now explicit for multi-statement transactions +BEGIN \; +CREATE TABLE foo(s TEXT) \; +INSERT INTO foo(s) VALUES ('hello'), ('world') \; +COMMIT; +BEGIN \; +DROP TABLE foo \; +ROLLBACK \; +-- implicit transactions +SELECT * FROM foo ORDER BY 1 \; +DROP TABLE foo; + s +------- + hello + world +(2 rows) + +-- +-- test ON_ERROR_ROLLBACK and combined queries +-- +CREATE FUNCTION psql_error(msg TEXT) RETURNS BOOLEAN AS $$ + BEGIN + RAISE EXCEPTION 'error %', msg; + END; +$$ LANGUAGE plpgsql; +\set ON_ERROR_ROLLBACK on +\echo '# ON_ERROR_ROLLBACK:' :ON_ERROR_ROLLBACK +# ON_ERROR_ROLLBACK: on +\echo '# AUTOCOMMIT:' :AUTOCOMMIT +# AUTOCOMMIT: on +BEGIN; +CREATE TABLE bla(s NO_SUCH_TYPE); -- fails +ERROR: type "no_such_type" does not exist +LINE 1: CREATE TABLE bla(s NO_SUCH_TYPE); + ^ +CREATE TABLE bla(s TEXT); -- succeeds +SELECT psql_error('oops!'); -- fails +ERROR: error oops! +CONTEXT: PL/pgSQL function psql_error(text) line 3 at RAISE +INSERT INTO bla VALUES ('Calvin'), ('Hobbes'); +COMMIT; +SELECT * FROM bla ORDER BY 1; + s +-------- + Calvin + Hobbes +(2 rows) + +BEGIN; +INSERT INTO bla VALUES ('Susie'); -- succeeds +-- now with combined queries +INSERT INTO bla VALUES ('Rosalyn') \; -- will rollback +SELECT 'before error' AS show \; -- will show nevertheless! + SELECT psql_error('boum!') \; -- failure + SELECT 'after error' AS noshow; -- hidden by preceding error + show +-------------- + before error +(1 row) + +ERROR: error boum! +CONTEXT: PL/pgSQL function psql_error(text) line 3 at RAISE +INSERT INTO bla(s) VALUES ('Moe') \; -- will rollback + SELECT psql_error('bam!'); +ERROR: error bam! +CONTEXT: PL/pgSQL function psql_error(text) line 3 at RAISE +INSERT INTO bla VALUES ('Miss Wormwood'); -- succeeds +COMMIT; +SELECT * FROM bla ORDER BY 1; + s +--------------- + Calvin + Hobbes + Miss Wormwood + Susie +(4 rows) + +-- some with autocommit off +\set AUTOCOMMIT off +\echo '# AUTOCOMMIT:' :AUTOCOMMIT +# AUTOCOMMIT: off +-- implicit BEGIN +INSERT INTO bla VALUES ('Dad'); -- succeeds +SELECT psql_error('bad!'); -- implicit partial rollback +ERROR: error bad! +CONTEXT: PL/pgSQL function psql_error(text) line 3 at RAISE +INSERT INTO bla VALUES ('Mum') \; -- will rollback +SELECT COUNT(*) AS "#mum" +FROM bla WHERE s = 'Mum' \; -- but be counted here +SELECT psql_error('bad!'); -- implicit partial rollback + #mum +------ + 1 +(1 row) + +ERROR: error bad! +CONTEXT: PL/pgSQL function psql_error(text) line 3 at RAISE +COMMIT; +SELECT COUNT(*) AS "#mum" +FROM bla WHERE s = 'Mum' \; -- no mum here +SELECT * FROM bla ORDER BY 1; + #mum +------ + 0 +(1 row) + + s +--------------- + Calvin + Dad + Hobbes + Miss Wormwood + Susie +(5 rows) + +COMMIT; +-- reset all +\set AUTOCOMMIT on +\set ON_ERROR_ROLLBACK off +\echo '# final ON_ERROR_ROLLBACK:' :ON_ERROR_ROLLBACK +# final ON_ERROR_ROLLBACK: off +DROP TABLE bla; +DROP FUNCTION psql_error; +-- check describing invalid multipart names +\dA regression.heap +improper qualified name (too many dotted names): regression.heap +\dA nonesuch.heap +improper qualified name (too many dotted names): nonesuch.heap +\dt host.regression.pg_catalog.pg_class +improper qualified name (too many dotted names): host.regression.pg_catalog.pg_class +\dt |.pg_catalog.pg_class +cross-database references are not implemented: |.pg_catalog.pg_class +\dt nonesuch.pg_catalog.pg_class +cross-database references are not implemented: nonesuch.pg_catalog.pg_class +\da host.regression.pg_catalog.sum +improper qualified name (too many dotted names): host.regression.pg_catalog.sum +\da +.pg_catalog.sum +cross-database references are not implemented: +.pg_catalog.sum +\da nonesuch.pg_catalog.sum +cross-database references are not implemented: nonesuch.pg_catalog.sum +\dAc nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAc regression.brin +improper qualified name (too many dotted names): regression.brin +\dAf nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAf regression.brin +improper qualified name (too many dotted names): regression.brin +\dAo nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAo regression.brin +improper qualified name (too many dotted names): regression.brin +\dAp nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAp regression.brin +improper qualified name (too many dotted names): regression.brin +\db nonesuch.pg_default +improper qualified name (too many dotted names): nonesuch.pg_default +\db regression.pg_default +improper qualified name (too many dotted names): regression.pg_default +\dc host.regression.public.conversion +improper qualified name (too many dotted names): host.regression.public.conversion +\dc (.public.conversion +cross-database references are not implemented: (.public.conversion +\dc nonesuch.public.conversion +cross-database references are not implemented: nonesuch.public.conversion +\dC host.regression.pg_catalog.int8 +improper qualified name (too many dotted names): host.regression.pg_catalog.int8 +\dC ).pg_catalog.int8 +cross-database references are not implemented: ).pg_catalog.int8 +\dC nonesuch.pg_catalog.int8 +cross-database references are not implemented: nonesuch.pg_catalog.int8 +\dd host.regression.pg_catalog.pg_class +improper qualified name (too many dotted names): host.regression.pg_catalog.pg_class +\dd [.pg_catalog.pg_class +cross-database references are not implemented: [.pg_catalog.pg_class +\dd nonesuch.pg_catalog.pg_class +cross-database references are not implemented: nonesuch.pg_catalog.pg_class +\dD host.regression.public.gtestdomain1 +improper qualified name (too many dotted names): host.regression.public.gtestdomain1 +\dD ].public.gtestdomain1 +cross-database references are not implemented: ].public.gtestdomain1 +\dD nonesuch.public.gtestdomain1 +cross-database references are not implemented: nonesuch.public.gtestdomain1 +\ddp host.regression.pg_catalog.pg_class +improper qualified name (too many dotted names): host.regression.pg_catalog.pg_class +\ddp {.pg_catalog.pg_class +cross-database references are not implemented: {.pg_catalog.pg_class +\ddp nonesuch.pg_catalog.pg_class +cross-database references are not implemented: nonesuch.pg_catalog.pg_class +\dE host.regression.public.ft +improper qualified name (too many dotted names): host.regression.public.ft +\dE }.public.ft +cross-database references are not implemented: }.public.ft +\dE nonesuch.public.ft +cross-database references are not implemented: nonesuch.public.ft +\di host.regression.public.tenk1_hundred +improper qualified name (too many dotted names): host.regression.public.tenk1_hundred +\di ..public.tenk1_hundred +improper qualified name (too many dotted names): ..public.tenk1_hundred +\di nonesuch.public.tenk1_hundred +cross-database references are not implemented: nonesuch.public.tenk1_hundred +\dm host.regression.public.mvtest_bb +improper qualified name (too many dotted names): host.regression.public.mvtest_bb +\dm ^.public.mvtest_bb +cross-database references are not implemented: ^.public.mvtest_bb +\dm nonesuch.public.mvtest_bb +cross-database references are not implemented: nonesuch.public.mvtest_bb +\ds host.regression.public.check_seq +improper qualified name (too many dotted names): host.regression.public.check_seq +\ds regression|mydb.public.check_seq +cross-database references are not implemented: regression|mydb.public.check_seq +\ds nonesuch.public.check_seq +cross-database references are not implemented: nonesuch.public.check_seq +\dt host.regression.public.b_star +improper qualified name (too many dotted names): host.regression.public.b_star +\dt regres+ion.public.b_star +cross-database references are not implemented: regres+ion.public.b_star +\dt nonesuch.public.b_star +cross-database references are not implemented: nonesuch.public.b_star +\dv host.regression.public.shoe +improper qualified name (too many dotted names): host.regression.public.shoe +\dv regress(ion).public.shoe +cross-database references are not implemented: regress(ion).public.shoe +\dv nonesuch.public.shoe +cross-database references are not implemented: nonesuch.public.shoe +\des nonesuch.server +improper qualified name (too many dotted names): nonesuch.server +\des regression.server +improper qualified name (too many dotted names): regression.server +\des nonesuch.server +improper qualified name (too many dotted names): nonesuch.server +\des regression.server +improper qualified name (too many dotted names): regression.server +\des nonesuch.username +improper qualified name (too many dotted names): nonesuch.username +\des regression.username +improper qualified name (too many dotted names): regression.username +\dew nonesuch.fdw +improper qualified name (too many dotted names): nonesuch.fdw +\dew regression.fdw +improper qualified name (too many dotted names): regression.fdw +\df host.regression.public.namelen +improper qualified name (too many dotted names): host.regression.public.namelen +\df regres[qrstuv]ion.public.namelen +cross-database references are not implemented: regres[qrstuv]ion.public.namelen +\df nonesuch.public.namelen +cross-database references are not implemented: nonesuch.public.namelen +\dF host.regression.pg_catalog.arabic +improper qualified name (too many dotted names): host.regression.pg_catalog.arabic +\dF regres{1,2}ion.pg_catalog.arabic +cross-database references are not implemented: regres{1,2}ion.pg_catalog.arabic +\dF nonesuch.pg_catalog.arabic +cross-database references are not implemented: nonesuch.pg_catalog.arabic +\dFd host.regression.pg_catalog.arabic_stem +improper qualified name (too many dotted names): host.regression.pg_catalog.arabic_stem +\dFd regres?ion.pg_catalog.arabic_stem +cross-database references are not implemented: regres?ion.pg_catalog.arabic_stem +\dFd nonesuch.pg_catalog.arabic_stem +cross-database references are not implemented: nonesuch.pg_catalog.arabic_stem +\dFp host.regression.pg_catalog.default +improper qualified name (too many dotted names): host.regression.pg_catalog.default +\dFp ^regression.pg_catalog.default +cross-database references are not implemented: ^regression.pg_catalog.default +\dFp nonesuch.pg_catalog.default +cross-database references are not implemented: nonesuch.pg_catalog.default +\dFt host.regression.pg_catalog.ispell +improper qualified name (too many dotted names): host.regression.pg_catalog.ispell +\dFt regression$.pg_catalog.ispell +cross-database references are not implemented: regression$.pg_catalog.ispell +\dFt nonesuch.pg_catalog.ispell +cross-database references are not implemented: nonesuch.pg_catalog.ispell +\dg nonesuch.pg_database_owner +improper qualified name (too many dotted names): nonesuch.pg_database_owner +\dg regression.pg_database_owner +improper qualified name (too many dotted names): regression.pg_database_owner +\dL host.regression.plpgsql +improper qualified name (too many dotted names): host.regression.plpgsql +\dL *.plpgsql +cross-database references are not implemented: *.plpgsql +\dL nonesuch.plpgsql +cross-database references are not implemented: nonesuch.plpgsql +\dn host.regression.public +improper qualified name (too many dotted names): host.regression.public +\dn """".public +cross-database references are not implemented: """".public +\dn nonesuch.public +cross-database references are not implemented: nonesuch.public +\do host.regression.public.!=- +improper qualified name (too many dotted names): host.regression.public.!=- +\do "regression|mydb".public.!=- +cross-database references are not implemented: "regression|mydb".public.!=- +\do nonesuch.public.!=- +cross-database references are not implemented: nonesuch.public.!=- +\dO host.regression.pg_catalog.POSIX +improper qualified name (too many dotted names): host.regression.pg_catalog.POSIX +\dO .pg_catalog.POSIX +cross-database references are not implemented: .pg_catalog.POSIX +\dO nonesuch.pg_catalog.POSIX +cross-database references are not implemented: nonesuch.pg_catalog.POSIX +\dp host.regression.public.a_star +improper qualified name (too many dotted names): host.regression.public.a_star +\dp "regres+ion".public.a_star +cross-database references are not implemented: "regres+ion".public.a_star +\dp nonesuch.public.a_star +cross-database references are not implemented: nonesuch.public.a_star +\dP host.regression.public.mlparted +improper qualified name (too many dotted names): host.regression.public.mlparted +\dP "regres(sion)".public.mlparted +cross-database references are not implemented: "regres(sion)".public.mlparted +\dP nonesuch.public.mlparted +cross-database references are not implemented: nonesuch.public.mlparted +\drds nonesuch.lc_messages +improper qualified name (too many dotted names): nonesuch.lc_messages +\drds regression.lc_messages +improper qualified name (too many dotted names): regression.lc_messages +\dRp public.mypub +improper qualified name (too many dotted names): public.mypub +\dRp regression.mypub +improper qualified name (too many dotted names): regression.mypub +\dRs public.mysub +improper qualified name (too many dotted names): public.mysub +\dRs regression.mysub +improper qualified name (too many dotted names): regression.mysub +\dT host.regression.public.widget +improper qualified name (too many dotted names): host.regression.public.widget +\dT "regression{1,2}".public.widget +cross-database references are not implemented: "regression{1,2}".public.widget +\dT nonesuch.public.widget +cross-database references are not implemented: nonesuch.public.widget +\dx regression.plpgsql +improper qualified name (too many dotted names): regression.plpgsql +\dx nonesuch.plpgsql +improper qualified name (too many dotted names): nonesuch.plpgsql +\dX host.regression.public.func_deps_stat +improper qualified name (too many dotted names): host.regression.public.func_deps_stat +\dX "^regression$".public.func_deps_stat +cross-database references are not implemented: "^regression$".public.func_deps_stat +\dX nonesuch.public.func_deps_stat +cross-database references are not implemented: nonesuch.public.func_deps_stat +\dy regression.myevt +improper qualified name (too many dotted names): regression.myevt +\dy nonesuch.myevt +improper qualified name (too many dotted names): nonesuch.myevt +-- check that dots within quoted name segments are not counted +\dA "no.such.access.method" +List of access methods + Name | Type +------+------ +(0 rows) + +\dt "no.such.table.relation" + List of tables + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\da "no.such.aggregate.function" + List of aggregate functions + Schema | Name | Result data type | Argument data types | Description +--------+------+------------------+---------------------+------------- +(0 rows) + +\dAc "no.such.operator.class" + List of operator classes + AM | Input type | Storage type | Operator class | Default? +----+------------+--------------+----------------+---------- +(0 rows) + +\dAf "no.such.operator.family" + List of operator families + AM | Operator family | Applicable types +----+-----------------+------------------ +(0 rows) + +\dAo "no.such.operator.of.operator.family" + List of operators of operator families + AM | Operator family | Operator | Strategy | Purpose +----+-----------------+----------+----------+--------- +(0 rows) + +\dAp "no.such.operator.support.function.of.operator.family" + List of support functions of operator families + AM | Operator family | Registered left type | Registered right type | Number | Function +----+-----------------+----------------------+-----------------------+--------+---------- +(0 rows) + +\db "no.such.tablespace" + List of tablespaces + Name | Owner | Location +------+-------+---------- +(0 rows) + +\dc "no.such.conversion" + List of conversions + Schema | Name | Source | Destination | Default? +--------+------+--------+-------------+---------- +(0 rows) + +\dC "no.such.cast" + List of casts + Source type | Target type | Function | Implicit? +-------------+-------------+----------+----------- +(0 rows) + +\dd "no.such.object.description" + Object descriptions + Schema | Name | Object | Description +--------+------+--------+------------- +(0 rows) + +\dD "no.such.domain" + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +--------+------+------+-----------+----------+---------+------- +(0 rows) + +\ddp "no.such.default.access.privilege" + Default access privileges + Owner | Schema | Type | Access privileges +-------+--------+------+------------------- +(0 rows) + +\di "no.such.index.relation" + List of indexes + Schema | Name | Type | Owner | Table +--------+------+------+-------+------- +(0 rows) + +\dm "no.such.materialized.view" + List of materialized views + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\ds "no.such.relation" + List of sequences + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dt "no.such.relation" + List of tables + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dv "no.such.relation" + List of views + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\des "no.such.foreign.server" + List of foreign servers + Name | Owner | Foreign-data wrapper +------+-------+---------------------- +(0 rows) + +\dew "no.such.foreign.data.wrapper" + List of foreign-data wrappers + Name | Owner | Handler | Validator +------+-------+---------+----------- +(0 rows) + +\df "no.such.function" + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + +\dF "no.such.text.search.configuration" +List of text search configurations + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFd "no.such.text.search.dictionary" +List of text search dictionaries + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFp "no.such.text.search.parser" + List of text search parsers + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFt "no.such.text.search.template" +List of text search templates + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dg "no.such.role" + List of roles + Role name | Attributes +-----------+------------ + +\dL "no.such.language" + List of languages + Name | Owner | Trusted | Description +------+-------+---------+------------- +(0 rows) + +\dn "no.such.schema" +List of schemas + Name | Owner +------+------- +(0 rows) + +\do "no.such.operator" + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +--------+------+---------------+----------------+-------------+------------- +(0 rows) + +\dO "no.such.collation" + List of collations + Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic? +--------+------+----------+---------+-------+--------+-----------+---------------- +(0 rows) + +\dp "no.such.access.privilege" + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+------+------+-------------------+-------------------+---------- +(0 rows) + +\dP "no.such.partitioned.relation" + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +--------+------+-------+------+-------------+------- +(0 rows) + +\drds "no.such.setting" + List of settings + Role | Database | Settings +------+----------+---------- +(0 rows) + +\dRp "no.such.publication" + List of publications + Name | Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root +------+-------+------------+---------+---------+---------+-----------+-------------------+---------- +(0 rows) + +\dRs "no.such.subscription" + List of subscriptions + Name | Owner | Enabled | Publication +------+-------+---------+------------- +(0 rows) + +\dT "no.such.data.type" + List of data types + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dx "no.such.installed.extension" + List of installed extensions + Name | Version | Default version | Schema | Description +------+---------+-----------------+--------+------------- +(0 rows) + +\dX "no.such.extended.statistics" + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+------+------------+-----------+--------------+----- +(0 rows) + +\dy "no.such.event.trigger" + List of event triggers + Name | Event | Owner | Enabled | Function | Tags +------+-------+-------+---------+----------+------ +(0 rows) + +-- again, but with dotted schema qualifications. +\dA "no.such.schema"."no.such.access.method" +improper qualified name (too many dotted names): "no.such.schema"."no.such.access.method" +\dt "no.such.schema"."no.such.table.relation" + List of tables + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\da "no.such.schema"."no.such.aggregate.function" + List of aggregate functions + Schema | Name | Result data type | Argument data types | Description +--------+------+------------------+---------------------+------------- +(0 rows) + +\dAc "no.such.schema"."no.such.operator.class" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.class" +\dAf "no.such.schema"."no.such.operator.family" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.family" +\dAo "no.such.schema"."no.such.operator.of.operator.family" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.of.operator.family" +\dAp "no.such.schema"."no.such.operator.support.function.of.operator.family" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.support.function.of.operator.family" +\db "no.such.schema"."no.such.tablespace" +improper qualified name (too many dotted names): "no.such.schema"."no.such.tablespace" +\dc "no.such.schema"."no.such.conversion" + List of conversions + Schema | Name | Source | Destination | Default? +--------+------+--------+-------------+---------- +(0 rows) + +\dC "no.such.schema"."no.such.cast" + List of casts + Source type | Target type | Function | Implicit? +-------------+-------------+----------+----------- +(0 rows) + +\dd "no.such.schema"."no.such.object.description" + Object descriptions + Schema | Name | Object | Description +--------+------+--------+------------- +(0 rows) + +\dD "no.such.schema"."no.such.domain" + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +--------+------+------+-----------+----------+---------+------- +(0 rows) + +\ddp "no.such.schema"."no.such.default.access.privilege" + Default access privileges + Owner | Schema | Type | Access privileges +-------+--------+------+------------------- +(0 rows) + +\di "no.such.schema"."no.such.index.relation" + List of indexes + Schema | Name | Type | Owner | Table +--------+------+------+-------+------- +(0 rows) + +\dm "no.such.schema"."no.such.materialized.view" + List of materialized views + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\ds "no.such.schema"."no.such.relation" + List of sequences + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dt "no.such.schema"."no.such.relation" + List of tables + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dv "no.such.schema"."no.such.relation" + List of views + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\des "no.such.schema"."no.such.foreign.server" +improper qualified name (too many dotted names): "no.such.schema"."no.such.foreign.server" +\dew "no.such.schema"."no.such.foreign.data.wrapper" +improper qualified name (too many dotted names): "no.such.schema"."no.such.foreign.data.wrapper" +\df "no.such.schema"."no.such.function" + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + +\dF "no.such.schema"."no.such.text.search.configuration" +List of text search configurations + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFd "no.such.schema"."no.such.text.search.dictionary" +List of text search dictionaries + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFp "no.such.schema"."no.such.text.search.parser" + List of text search parsers + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFt "no.such.schema"."no.such.text.search.template" +List of text search templates + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dg "no.such.schema"."no.such.role" +improper qualified name (too many dotted names): "no.such.schema"."no.such.role" +\dL "no.such.schema"."no.such.language" +cross-database references are not implemented: "no.such.schema"."no.such.language" +\do "no.such.schema"."no.such.operator" + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +--------+------+---------------+----------------+-------------+------------- +(0 rows) + +\dO "no.such.schema"."no.such.collation" + List of collations + Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic? +--------+------+----------+---------+-------+--------+-----------+---------------- +(0 rows) + +\dp "no.such.schema"."no.such.access.privilege" + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+------+------+-------------------+-------------------+---------- +(0 rows) + +\dP "no.such.schema"."no.such.partitioned.relation" + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +--------+------+-------+------+-------------+------- +(0 rows) + +\drds "no.such.schema"."no.such.setting" +improper qualified name (too many dotted names): "no.such.schema"."no.such.setting" +\dRp "no.such.schema"."no.such.publication" +improper qualified name (too many dotted names): "no.such.schema"."no.such.publication" +\dRs "no.such.schema"."no.such.subscription" +improper qualified name (too many dotted names): "no.such.schema"."no.such.subscription" +\dT "no.such.schema"."no.such.data.type" + List of data types + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dx "no.such.schema"."no.such.installed.extension" +improper qualified name (too many dotted names): "no.such.schema"."no.such.installed.extension" +\dX "no.such.schema"."no.such.extended.statistics" + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+------+------------+-----------+--------------+----- +(0 rows) + +\dy "no.such.schema"."no.such.event.trigger" +improper qualified name (too many dotted names): "no.such.schema"."no.such.event.trigger" +-- again, but with current database and dotted schema qualifications. +\dt regression."no.such.schema"."no.such.table.relation" + List of tables + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\da regression."no.such.schema"."no.such.aggregate.function" + List of aggregate functions + Schema | Name | Result data type | Argument data types | Description +--------+------+------------------+---------------------+------------- +(0 rows) + +\dc regression."no.such.schema"."no.such.conversion" + List of conversions + Schema | Name | Source | Destination | Default? +--------+------+--------+-------------+---------- +(0 rows) + +\dC regression."no.such.schema"."no.such.cast" + List of casts + Source type | Target type | Function | Implicit? +-------------+-------------+----------+----------- +(0 rows) + +\dd regression."no.such.schema"."no.such.object.description" + Object descriptions + Schema | Name | Object | Description +--------+------+--------+------------- +(0 rows) + +\dD regression."no.such.schema"."no.such.domain" + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +--------+------+------+-----------+----------+---------+------- +(0 rows) + +\di regression."no.such.schema"."no.such.index.relation" + List of indexes + Schema | Name | Type | Owner | Table +--------+------+------+-------+------- +(0 rows) + +\dm regression."no.such.schema"."no.such.materialized.view" + List of materialized views + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\ds regression."no.such.schema"."no.such.relation" + List of sequences + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dt regression."no.such.schema"."no.such.relation" + List of tables + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dv regression."no.such.schema"."no.such.relation" + List of views + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\df regression."no.such.schema"."no.such.function" + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + +\dF regression."no.such.schema"."no.such.text.search.configuration" +List of text search configurations + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFd regression."no.such.schema"."no.such.text.search.dictionary" +List of text search dictionaries + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFp regression."no.such.schema"."no.such.text.search.parser" + List of text search parsers + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFt regression."no.such.schema"."no.such.text.search.template" +List of text search templates + Schema | Name | Description +--------+------+------------- +(0 rows) + +\do regression."no.such.schema"."no.such.operator" + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +--------+------+---------------+----------------+-------------+------------- +(0 rows) + +\dO regression."no.such.schema"."no.such.collation" + List of collations + Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic? +--------+------+----------+---------+-------+--------+-----------+---------------- +(0 rows) + +\dp regression."no.such.schema"."no.such.access.privilege" + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+------+------+-------------------+-------------------+---------- +(0 rows) + +\dP regression."no.such.schema"."no.such.partitioned.relation" + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +--------+------+-------+------+-------------+------- +(0 rows) + +\dT regression."no.such.schema"."no.such.data.type" + List of data types + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dX regression."no.such.schema"."no.such.extended.statistics" + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+------+------------+-----------+--------------+----- +(0 rows) + +-- again, but with dotted database and dotted schema qualifications. +\dt "no.such.database"."no.such.schema"."no.such.table.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.table.relation" +\da "no.such.database"."no.such.schema"."no.such.aggregate.function" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.aggregate.function" +\dc "no.such.database"."no.such.schema"."no.such.conversion" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.conversion" +\dC "no.such.database"."no.such.schema"."no.such.cast" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.cast" +\dd "no.such.database"."no.such.schema"."no.such.object.description" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.object.description" +\dD "no.such.database"."no.such.schema"."no.such.domain" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.domain" +\ddp "no.such.database"."no.such.schema"."no.such.default.access.privilege" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.default.access.privilege" +\di "no.such.database"."no.such.schema"."no.such.index.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.index.relation" +\dm "no.such.database"."no.such.schema"."no.such.materialized.view" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.materialized.view" +\ds "no.such.database"."no.such.schema"."no.such.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.relation" +\dt "no.such.database"."no.such.schema"."no.such.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.relation" +\dv "no.such.database"."no.such.schema"."no.such.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.relation" +\df "no.such.database"."no.such.schema"."no.such.function" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.function" +\dF "no.such.database"."no.such.schema"."no.such.text.search.configuration" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.configuration" +\dFd "no.such.database"."no.such.schema"."no.such.text.search.dictionary" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.dictionary" +\dFp "no.such.database"."no.such.schema"."no.such.text.search.parser" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.parser" +\dFt "no.such.database"."no.such.schema"."no.such.text.search.template" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.template" +\do "no.such.database"."no.such.schema"."no.such.operator" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.operator" +\dO "no.such.database"."no.such.schema"."no.such.collation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.collation" +\dp "no.such.database"."no.such.schema"."no.such.access.privilege" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.access.privilege" +\dP "no.such.database"."no.such.schema"."no.such.partitioned.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.partitioned.relation" +\dT "no.such.database"."no.such.schema"."no.such.data.type" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.data.type" +\dX "no.such.database"."no.such.schema"."no.such.extended.statistics" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.extended.statistics" +-- check \drg and \du +CREATE ROLE regress_du_role0; +CREATE ROLE regress_du_role1; +CREATE ROLE regress_du_role2; +CREATE ROLE regress_du_admin; +GRANT regress_du_role0 TO regress_du_admin WITH ADMIN TRUE; +GRANT regress_du_role1 TO regress_du_admin WITH ADMIN TRUE; +GRANT regress_du_role2 TO regress_du_admin WITH ADMIN TRUE; +GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN TRUE, INHERIT TRUE, SET TRUE GRANTED BY regress_du_admin; +GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN TRUE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_admin; +GRANT regress_du_role1 TO regress_du_role2 WITH ADMIN TRUE , INHERIT FALSE, SET TRUE GRANTED BY regress_du_admin; +GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT TRUE, SET FALSE GRANTED BY regress_du_role1; +GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT TRUE , SET TRUE GRANTED BY regress_du_role1; +GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT FALSE, SET TRUE GRANTED BY regress_du_role2; +GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_role2; +\drg regress_du_role* + List of role grants + Role name | Member of | Options | Grantor +------------------+------------------+---------------------+------------------ + regress_du_role1 | regress_du_role0 | ADMIN, INHERIT, SET | regress_du_admin + regress_du_role1 | regress_du_role0 | INHERIT | regress_du_role1 + regress_du_role1 | regress_du_role0 | SET | regress_du_role2 + regress_du_role2 | regress_du_role0 | ADMIN | regress_du_admin + regress_du_role2 | regress_du_role0 | INHERIT, SET | regress_du_role1 + regress_du_role2 | regress_du_role0 | | regress_du_role2 + regress_du_role2 | regress_du_role1 | ADMIN, SET | regress_du_admin +(7 rows) + +\du regress_du_role* + List of roles + Role name | Attributes +------------------+-------------- + regress_du_role0 | Cannot login + regress_du_role1 | Cannot login + regress_du_role2 | Cannot login + +DROP ROLE regress_du_role0; +DROP ROLE regress_du_role1; +DROP ROLE regress_du_role2; +DROP ROLE regress_du_admin; +-- Test display of empty privileges. +BEGIN; +-- Create an owner for tested objects because output contains owner name. +CREATE ROLE regress_zeropriv_owner; +SET LOCAL ROLE regress_zeropriv_owner; +CREATE DOMAIN regress_zeropriv_domain AS int; +REVOKE ALL ON DOMAIN regress_zeropriv_domain FROM CURRENT_USER, PUBLIC; +\dD+ regress_zeropriv_domain + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check | Access privileges | Description +--------+-------------------------+---------+-----------+----------+---------+-------+-------------------+------------- + public | regress_zeropriv_domain | integer | | | | | (none) | +(1 row) + +CREATE PROCEDURE regress_zeropriv_proc() LANGUAGE sql AS ''; +REVOKE ALL ON PROCEDURE regress_zeropriv_proc() FROM CURRENT_USER, PUBLIC; +\df+ regress_zeropriv_proc + List of functions + Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Leakproof? | Access privileges | Language | Internal name | Description +--------+-----------------------+------------------+---------------------+------+------------+----------+------------------------+----------+------------+-------------------+----------+---------------+------------- + public | regress_zeropriv_proc | | | proc | volatile | unsafe | regress_zeropriv_owner | invoker | no | (none) | sql | | +(1 row) + +CREATE TABLE regress_zeropriv_tbl (a int); +REVOKE ALL ON TABLE regress_zeropriv_tbl FROM CURRENT_USER; +\dp regress_zeropriv_tbl + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+----------------------+-------+-------------------+-------------------+---------- + public | regress_zeropriv_tbl | table | (none) | | +(1 row) + +CREATE TYPE regress_zeropriv_type AS (a int); +REVOKE ALL ON TYPE regress_zeropriv_type FROM CURRENT_USER, PUBLIC; +\dT+ regress_zeropriv_type + List of data types + Schema | Name | Internal name | Size | Elements | Owner | Access privileges | Description +--------+-----------------------+-----------------------+-------+----------+------------------------+-------------------+------------- + public | regress_zeropriv_type | regress_zeropriv_type | tuple | | regress_zeropriv_owner | (none) | +(1 row) + +ROLLBACK; +-- Test display of default privileges with \pset null. +CREATE TABLE defprivs (a int); +\pset null '(default)' +\z defprivs + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+----------+-------+-------------------+-------------------+---------- + public | defprivs | table | (default) | | +(1 row) + +\zx defprivs +Access privileges +-[ RECORD 1 ]-----+---------- +Schema | public +Name | defprivs +Type | table +Access privileges | (default) +Column privileges | +Policies | + +\pset null '' +DROP TABLE defprivs; diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 5d85dcc62f0a5..7c177545245b3 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -102,6 +102,7 @@ char *expecteddir = "."; char *bindir = PGBINDIR; char *launcher = NULL; static _stringlist *loadextension = NULL; +char *exec_sql = NULL; static int max_connections = 0; static int max_concurrent_tests = 0; static char *encoding = NULL; @@ -1988,6 +1989,26 @@ create_database(const char *dbname) */ for (sl = loadextension; sl != NULL; sl = sl->next) psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str); + + /* + * Percona extension Execute any additional sql commands provided by + * caller + */ + if (exec_sql) + { + FILE *sql_file; + char line_buf[2048]; + + sql_file = fopen(exec_sql, "r"); + if (sql_file == NULL) + { + bail("could not open \"%s\" to read extra setup file: %m", + exec_sql); + } + while (fgets(line_buf, sizeof(line_buf), sql_file) != NULL) + psql_command(dbname, "%s", line_buf); + fclose(sql_file); + } } static void @@ -2037,6 +2058,8 @@ help(void) printf(_(" --launcher=CMD use CMD as launcher of psql\n")); printf(_(" --load-extension=EXT load the named extension before running the\n")); printf(_(" tests; can appear multiple times\n")); + printf(_(" --extra-setup=FILE file containing optional SQL commands to run before running the\n")); + printf(_(" tests;\n")); printf(_(" --max-connections=N maximum number of concurrent connections\n")); printf(_(" (default is 0, meaning unlimited)\n")); printf(_(" --max-concurrent-tests=N maximum number of concurrent tests in schedule\n")); @@ -2096,6 +2119,7 @@ regression_main(int argc, char *argv[], {"config-auth", required_argument, NULL, 24}, {"max-concurrent-tests", required_argument, NULL, 25}, {"expecteddir", required_argument, NULL, 26}, + {"extra-setup", required_argument, NULL, 27}, {NULL, 0, NULL, 0} }; @@ -2224,6 +2248,9 @@ regression_main(int argc, char *argv[], case 26: expecteddir = pg_strdup(optarg); break; + case 27: + exec_sql = pg_strdup(optarg); + break; default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 38620a595c14f..757c91c129308 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1661,6 +1661,7 @@ Material MaterialPath MaterialState MdPathStr +MdSMgrRelationData MdfdVec Memoize MemoizeEntry @@ -3347,6 +3348,7 @@ XLogRecordBuffer XLogRecoveryCtlData XLogRedoAction XLogSegNo +XLogSmgr XLogSource XLogStats XLogwrtResult