Compare commits

...

31 Commits
main ... v9.3.4

Author SHA1 Message Date
Hanefi Onaldi 5bf2074dce
Introduce downgrade scripts for 9.3 versions (#4051)
Here are the updated make targets:
- install: install everything except downgrade scripts.
- install-downgrades: build and install only the downgrade migration scripts.
- install-all: install everything along with the downgrade migration scripts.

(cherry picked from commit 315b323d47)

This commit is heavily modified to support an earlier release version.
- Downgrade scripts that are relevant for versions 9.4+ are stripped
- multi_extension tests are copied from master and then stripped
2020-07-21 17:38:07 +03:00
Onur Tirtir e221e4bbef Update CHANGELOG for 9.3.4
(cherry picked from commit 9e12a39cb7)
2020-07-21 14:06:03 +03:00
Onur Tirtir 2f4f2a2551
Bump version to 9.3.4 (#4050) 2020-07-21 13:06:50 +03:00
Hanefi Önaldı a2ba76db96
Accept list of values in a supported ALTER ROLE .. SET statement
Some GUCs support a list of values which is indicated by GUC_LIST_INPUT flag.

When an ALTER ROLE .. SET statement is executed, the new configuration
default for affected users and databases are stored in the
setconfig(text[]) column in a pg_db_role_setting record.

If a GUC that supports a list of values is used in an ALTER ROLE .. SET
statement, we need to split the text into items delimited by commas.

(cherry picked from commit e534dbae4a)
2020-07-21 04:13:32 +03:00
Marco Slot 0bb23cb3d4 Prevent integer overflow in FindShardIntervalIndex 2020-07-16 14:58:12 +02:00
Nils Dijk 5a27a8340e
fix flappy tests due to undeterministic order of test output (#4029)
As reported on #4011 https://github.com/citusdata/citus/pull/4011/files#r453804702 some of the tests were flapping due to an indeterministic order for test outputs.

This PR makes the test output ordered for all tests returning non-zero rows.

Needs to be backported to 9.2, 9.3, 9.4
2020-07-14 15:49:10 +02:00
Nils Dijk 4825447ed4
force aliases in deparsing for queries with anonymous column references (#4011)
DESCRIPTION: Force aliases in deparsing for queries with anonymous column references

Fixes: #3985

The root cause has todo with discrepancies in the query tree we create. I think in the future we should spend some time on categorising all changes we made to ruleutils and see if we can change the data structure `query` we pass to the deparser to have an actual valid postgres query for the deparser to render.

For now the fix is to keep track, besides changing the names of the entries in the target list, also if we have a reference to an anonymous columns. If there are anonymous columns we set the `printaliases` flag to true which forces the deparser to add the aliases.
2020-07-13 18:14:51 +02:00
Onur Tirtir ccb9b8fd51 Update CHANGELOG for 9.3.3
(cherry picked from commit 4c26bb5ffc)
2020-07-10 17:52:42 +03:00
Onur Tirtir 4c9e031974
Bump version to 9.3.3 (#4022) 2020-07-10 16:18:24 +03:00
Hadi Moshayedi df1cbdd1e3 Fix Subtransaction memory leak
(cherry picked from commit 3651fc64ee)
2020-07-10 10:27:21 +03:00
Onur Tirtir 4f574c1712
Merge pull request #3932 from citusdata/release-9.3-push-1592827707
Bump version to 9.3.2 in release-9.3 & Update CHANGELOG
2020-06-22 16:59:51 +03:00
Onur Tirtir 06bfe70cc9 Update CHANGELOG for 9.3.2
(cherry picked from commit d41ad47579)

 Conflicts:
	CHANGELOG.md
2020-06-22 16:30:02 +03:00
Onur Tirtir a6b65e0de3 Bump version to 9.3.2 2020-06-22 15:08:31 +03:00
Onur Tirtir db945e0ca1
Bump version to 9.3.1 (#3928) 2020-06-22 13:19:32 +03:00
Onur Tirtir 85f2703bec Update CHANGELOG for 9.3.1
(cherry picked from commit 4640f90933)

Conflicts:
	CHANGELOG.md
2020-06-17 19:12:33 +03:00
Nils Dijk 73ca2b9382
fix test output for tdigest (#3909)
Due to the problem described in #3908 we don't cover the tdigest integration (and other extensions) on CI.

Due to this a bug got in the patch due to a change in `EXPLAIN VERBOSE` being merged concurrently with the tdigest integration. This PR fixes the test output that missed the newly added information.

(cherry picked from commit f57711b3d2)
2020-06-17 14:36:43 +02:00
Nils Dijk f3f93ffb82
Feature: tdigest aggregate (#3897)
DESCRIPTION: Adds support to partially push down tdigest aggregates

tdigest extensions: https://github.com/tvondra/tdigest

This PR implements the partial pushdown of tdigest calculations when possible. The extension adds a tdigest type which can be combined into the same structure. There are several aggregate functions that can be used to get;
 - a quantile
 - a list of quantiles
 - the quantile of a hypothetical value
 - a list of quantiles for a list of hypothetical values

These function can work both on values or tdigest types.

Since we can create tdigest values either by combining them, or based on a group of values we can rewrite the aggregates in such a way that most of the computation gets delegated to the compute on the shards. This both speeds up the percentile calculations because the values don't have to be sorted while at the same time making the transfer size from the shards to the coordinator significantly less.

(cherry picked from commit da8f2b0134)
2020-06-17 14:36:15 +02:00
Onder Kalaci 885c77d0ae Coerce types properly for INSERT
Also, unify similar code-paths to rely on more accurate function.

(cherry picked from commit 06461ca55f)
2020-06-10 13:55:45 +02:00
Onur Tirtir 95c4aed73b Add changelog entry for 9.3.0 (#3823)
(cherry picked from commit ac1ec40bfb)
2020-05-07 16:11:53 +03:00
Nils Dijk 7973d43ba4 Fix for pruned target list entries (#3818)
DESCRIPTION: Ignore pruned target list entries in coordinator plan

The postgres planner has the ability to prune target list entries that are proven not used in the output relation. When this happens at the `CitusCustomScan` boundary we need to _not_ return these pruned columns to not upset the rest of the planner.

By using the target list the planner asks us to return we fix issues that lead to Assertion failures, and potentially could be runtime errors when they hit in a production build.

Fixes #3809
(cherry picked from commit 105de7beb8)
2020-05-06 15:18:41 +03:00
Hadi Moshayedi e7e36dddca Don't error out when cannot create maintenanced
(cherry picked from commit dbf509bbdd)
2020-05-06 15:16:52 +03:00
Marco Slot 2b8db771ef Make sure we don't wrap GROUP BY expressions in any_value 2020-05-06 06:26:28 +02:00
Onder Kalaci 5474508c01 Rebuild wait event sets after PQconnectPoll() if socket changes
The reason is that PQconnectPoll() may change the underlying
socket. If we don't rebuild the wait event set, the low level
APIs (such as epoll_ctl()) may fail due to invalid sockets.
Instead, rebuilding ensures that we'll use accurate/active sockets.

(cherry picked from commit 77c397e9ae)
2020-05-04 09:02:48 +02:00
Jelte Fennema 8f9b1a839f Add some asserts to pass static analysis (#3805)
(cherry picked from commit c6f5d5fe88)
2020-04-29 11:19:47 +02:00
SaitTalhaNisanci 15fc7821a8 Fix task copy and appending empty task in ExtractLocalAndRemoteTasks (#3802)
* Not append empty task in ExtractLocalAndRemoteTasks

ExtractLocalAndRemoteTasks extracts the local and remote tasks. If we do
not have a local task the localTaskPlacementList will be NIL, in this
case we should not append anything to local tasks. Previously we would
first check if a task contains a single placement or not, now we first
check if there is any local task before doing anything.

* fix copy of node task

Task node has task query, which might contain a list of strings in its
fields. We were using postgres copyObject for these lists. Postgres
assumes that each element of list will be a node type. If it is not a
node type it will error.

As a solution to that, a new macro is introduced to copy a list of
strings.

(cherry picked from commit cbda951395)
2020-04-29 11:41:15 +03:00
Philip Dubé 962bdc67af Fix COPY TO's COPY (SELECT) with distributed table having generated columns
It's necessary to omit generated columns from output

(cherry picked from commit b6b3c1bc17)
2020-04-29 10:50:01 +03:00
SaitTalhaNisanci f7f1b6cc5e Fix typo: longer visible -> no longer visible (#3803) 2020-04-27 16:40:33 +03:00
Onder Kalaci 128273393f Increase the default value of citus.node_connection_timeout
The previous default was 5 seconds, and we change it to 30 seconds.
The main motivation for this is that for busy clusters, 5 seconds
can be too aggressive. Especially with connection throttling, the servers
might be kept busy for a really long time, and users may see the
connection errors more frequently.

We've done some sanity checks, for really quick queries (like
`SELECT count(*) from table`), 30 seconds is a decent value even
if users execute 300 distributed queries on the coordinator. We've
verified this on Hyperscale(Citus).

(cherry picked from commit bc54c5125f)
2020-04-24 16:35:29 +02:00
Onder Kalaci 95ba5dd39c Explicitly mark queries in physical planner for [not] having parameters
Physical planner doesn't support parameters. If the parameters have already
been resolved when the physical planner handling the queries, mark it.
The reason is that the executor is unaware of this, and sends the parameters
along with the worker queries, which fails for composite types.

(See `DissuadePlannerFromUsingPlan()` for the details of paramater resolving)

(cherry picked from commit 0cb7ab2d05)
2020-04-24 13:23:41 +02:00
Onur Tirtir 80da0ed69a Fix build issue in GCC 10 (#3790)
As reported in #3787, we were having issues while building citus with "GCC Red Hat 10" (maybe in some other versions of gcc as well).
Fixes "multiple definition of 'CitusNodeTagNames'" error by explicitly specifying storage of CitusNodeTagNames to be extern.
(cherry picked from commit b8dd8f50d1)
2020-04-22 17:45:08 +03:00
Onur Tirtir 64f9ba2746 Bump Citus version to 9.3.0 2020-04-22 10:22:42 +03:00
109 changed files with 4223 additions and 304 deletions

View File

@ -1,3 +1,103 @@
### citus v9.3.4 (July 21, 2020) ###
* Fixes a bug that could cause crashes with certain compile flags
* Fixes a bug with lists of configuration values in ALTER ROLE SET statements
* Fixes deparsing for queries with anonymous column references
### citus v9.3.3 (July 10, 2020) ###
* Fixes a memory leak in subtransaction memory handling
### citus v9.3.2 (Jun 22, 2020) ###
* Fixes a version bump issue in 9.3.1
### citus v9.3.1 (Jun 17, 2020) ###
* Adds support to partially push down tdigest aggregates
* Fixes a crash that occurs when inserting implicitly coerced constants
### citus v9.3.0 (May 6, 2020) ###
* Adds `max_shared_pool_size` to control number of connections across sessions
* Adds support for window functions on coordinator
* Improves shard pruning logic to understand OR-conditions
* Prevents using an extra connection for intermediate result multi-casts
* Adds propagation of `ALTER ROLE .. SET` statements
* Adds `update_distributed_table_colocation` UDF to update colocation of tables
* Introduces a UDF to truncate local data after distributing a table
* Adds support for creating temp schemas in parallel
* Adds support for evaluation of `nextval` in the target list on coordinator
* Adds support for local execution of `COPY/TRUNCATE/DROP/DDL` commands
* Adds support for local execution of shard creation
* Uses local execution in a transaction block
* Adds support for querying distributed table sizes concurrently
* Allows `master_copy_shard_placement` to replicate placements to new nodes
* Allows table type to be used in target list
* Avoids having multiple maintenance daemons active for a single database
* Defers reference table replication to shard creation time
* Enables joins between local tables and reference tables in transaction blocks
* Ignores pruned target list entries in coordinator plan
* Improves `SIGTERM` handling of maintenance daemon
* Increases the default of `citus.node_connection_timeout` to 30 seconds
* Fixes a bug that occurs when creating remote tasks in local execution
* Fixes a bug that causes some DML queries containing aggregates to fail
* Fixes a bug that could cause failures in queries with subqueries or CTEs
* Fixes a bug that may cause some connection failures to throw errors
* Fixes a bug which caused queries with SRFs and function evalution to fail
* Fixes a bug with generated columns when executing `COPY dist_table TO file`
* Fixes a crash when using non-constant limit clauses
* Fixes a failure when composite types used in prepared statements
* Fixes a possible segfault when dropping dist. table in a transaction block
* Fixes a possible segfault when non-pushdownable aggs are solely used in HAVING
* Fixes a segfault when executing queries using `GROUPING`
* Fixes an error when using `LEFT JOIN with GROUP BY` on primary key
* Fixes an issue with distributing tables having generated cols not at the end
* Fixes automatic SSL permission issue when using "initdb --allow-group-access"
* Fixes errors which could occur when subqueries are parameters to aggregates
* Fixes possible issues by invalidating the plan cache in `master_update_node`
* Fixes timing issues which could be caused by changing system clock
### citus v9.2.4 (March 30, 2020) ###
* Fixes a release problem in 9.2.3

View File

@ -24,6 +24,7 @@ install-headers: extension
$(INSTALL_DATA) $(citus_top_builddir)/src/include/citus_version.h '$(DESTDIR)$(includedir_server)/'
# the rest in the source tree
$(INSTALL_DATA) $(citus_abs_srcdir)/src/include/distributed/*.h '$(DESTDIR)$(includedir_server)/distributed/'
clean-extension:
$(MAKE) -C src/backend/distributed/ clean
clean-full:
@ -31,6 +32,11 @@ clean-full:
.PHONY: extension install-extension clean-extension clean-full
# Add to generic targets
install: install-extension install-headers
install-downgrades:
$(MAKE) -C src/backend/distributed/ install-downgrades
install-all: install-headers
$(MAKE) -C src/backend/distributed/ install-all
clean: clean-extension
# apply or check style
@ -44,4 +50,4 @@ check-style:
check: all install
$(MAKE) -C src/test/regress check-full
.PHONY: all check install clean
.PHONY: all check clean install install-downgrades install-all

32
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for Citus 9.3devel.
# Generated by GNU Autoconf 2.69 for Citus 9.3.4.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -579,8 +579,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='Citus'
PACKAGE_TARNAME='citus'
PACKAGE_VERSION='9.3devel'
PACKAGE_STRING='Citus 9.3devel'
PACKAGE_VERSION='9.3.4'
PACKAGE_STRING='Citus 9.3.4'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@ -664,6 +664,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@ -740,6 +741,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -992,6 +994,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1129,7 +1140,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@ -1242,7 +1253,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures Citus 9.3devel to adapt to many kinds of systems.
\`configure' configures Citus 9.3.4 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1282,6 +1293,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -1303,7 +1315,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of Citus 9.3devel:";;
short | recursive ) echo "Configuration of Citus 9.3.4:";;
esac
cat <<\_ACEOF
@ -1403,7 +1415,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
Citus configure 9.3devel
Citus configure 9.3.4
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1886,7 +1898,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by Citus $as_me 9.3devel, which was
It was created by Citus $as_me 9.3.4, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -5055,7 +5067,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by Citus $as_me 9.3devel, which was
This file was extended by Citus $as_me 9.3.4, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -5117,7 +5129,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
Citus config.status 9.3devel
Citus config.status 9.3.4
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -5,7 +5,7 @@
# everyone needing autoconf installed, the resulting files are checked
# into the SCM.
AC_INIT([Citus], [9.3devel])
AC_INIT([Citus], [9.3.4])
AC_COPYRIGHT([Copyright (c) Citus Data, Inc.])
# we'll need sed and awk for some of the version commands

View File

@ -11,7 +11,9 @@ MODULE_big = citus
EXTENSION = citus
template_sql_files = $(patsubst $(citus_abs_srcdir)/%,%,$(wildcard $(citus_abs_srcdir)/sql/*.sql))
template_downgrade_sql_files = $(patsubst $(citus_abs_srcdir)/sql/downgrades/%,%,$(wildcard $(citus_abs_srcdir)/sql/downgrades/*.sql))
generated_sql_files = $(patsubst %,$(citus_abs_srcdir)/build/%,$(template_sql_files))
generated_downgrade_sql_files += $(patsubst %,$(citus_abs_srcdir)/build/sql/%,$(template_downgrade_sql_files))
# All citus--*.sql files that are used to upgrade between versions
DATA_built = $(generated_sql_files)
@ -54,6 +56,20 @@ SQL_BUILDDIR=build/sql
$(generated_sql_files): $(citus_abs_srcdir)/build/%: %
@mkdir -p $(citus_abs_srcdir)/$(SQL_DEPDIR) $(citus_abs_srcdir)/$(SQL_BUILDDIR)
@# -MF is used to store dependency files(.Po) in another directory for separation
@# -MT is used to change the target of the rule emitted by dependency generation.
@# -P is used to inhibit generation of linemarkers in the output from the preprocessor.
@# -undef is used to not predefine any system-specific or GCC-specific macros.
@# `man cpp` for further information
cd $(citus_abs_srcdir) && cpp -undef -w -P -MMD -MP -MF$(SQL_DEPDIR)/$(*F).Po -MT$@ $< > $@
$(generated_downgrade_sql_files): $(citus_abs_srcdir)/build/sql/%: sql/downgrades/%
@mkdir -p $(citus_abs_srcdir)/$(SQL_DEPDIR) $(citus_abs_srcdir)/$(SQL_BUILDDIR)
@# -MF is used to store dependency files(.Po) in another directory for separation
@# -MT is used to change the target of the rule emitted by dependency generation.
@# -P is used to inhibit generation of linemarkers in the output from the preprocessor.
@# -undef is used to not predefine any system-specific or GCC-specific macros.
@# `man cpp` for further information
cd $(citus_abs_srcdir) && cpp -undef -w -P -MMD -MP -MF$(SQL_DEPDIR)/$(*F).Po -MT$@ $< > $@
SQL_Po_files := $(wildcard $(SQL_DEPDIR)/*.Po)
@ -61,7 +77,7 @@ ifneq (,$(SQL_Po_files))
include $(SQL_Po_files)
endif
.PHONY: check-sql-snapshots clean-full
.PHONY: clean-full install install-downgrades install-all
check-sql-snapshots:
bash -c '\
@ -76,6 +92,13 @@ cleanup-before-install:
install: cleanup-before-install
# install and install-downgrades should be run sequentially
install-all: install
make install-downgrades
install-downgrades: $(generated_downgrade_sql_files)
$(INSTALL_DATA) $(generated_downgrade_sql_files) '$(DESTDIR)$(datadir)/$(datamoduledir)/'
clean-full:
make clean
rm -rf $(safestringlib_builddir)

View File

@ -116,19 +116,18 @@ CallFuncExprRemotely(CallStmt *callStmt, DistObjectCacheEntry *procedure,
ereport(DEBUG1, (errmsg("distribution argument value must be a constant")));
return false;
}
Const *partitionValue = (Const *) partitionValueNode;
Datum partitionValueDatum = partitionValue->constvalue;
Const *partitionValue = (Const *) partitionValueNode;
if (partitionValue->consttype != partitionColumn->vartype)
{
CopyCoercionData coercionData;
bool missingOk = false;
ConversionPathForTypes(partitionValue->consttype, partitionColumn->vartype,
&coercionData);
partitionValueDatum = CoerceColumnValue(partitionValueDatum, &coercionData);
partitionValue =
TransformPartitionRestrictionValue(partitionColumn, partitionValue,
missingOk);
}
Datum partitionValueDatum = partitionValue->constvalue;
ShardInterval *shardInterval = FindShardInterval(partitionValueDatum, distTable);
if (shardInterval == NULL)
{

View File

@ -1345,7 +1345,7 @@ DoCopyFromLocalTableIntoShards(Relation distributedRelation,
char *qualifiedRelationName =
generate_qualified_relation_name(RelationGetRelid(distributedRelation));
ereport(NOTICE, (errmsg("copying the data has completed"),
errdetail("The local data in the table is longer visible, "
errdetail("The local data in the table is no longer visible, "
"but is still on disk."),
errhint("To remove the local data, run: SELECT "
"truncate_local_data_after_distributing_table($$%s$$)",

View File

@ -264,6 +264,7 @@ static void EndPlacementStateCopyCommand(CopyPlacementState *placementState,
static void UnclaimCopyConnections(List *connectionStateList);
static void ShutdownCopyConnectionState(CopyConnectionState *connectionState,
CitusCopyDestReceiver *copyDest);
static SelectStmt * CitusCopySelect(CopyStmt *copyStatement);
static void CitusCopyTo(CopyStmt *copyStatement, char *completionTag);
static int64 ForwardCopyDataFromConnection(CopyOutState copyOutState,
MultiConnection *connection);
@ -2760,22 +2761,9 @@ ProcessCopyStmt(CopyStmt *copyStatement, char *completionTag, const char *queryS
{
/*
* COPY table TO PROGRAM / file is handled by wrapping the table
* in a SELECT * FROM table and going through the result COPY logic.
* in a SELECT and going through the resulting COPY logic.
*/
ColumnRef *allColumns = makeNode(ColumnRef);
SelectStmt *selectStmt = makeNode(SelectStmt);
ResTarget *selectTarget = makeNode(ResTarget);
allColumns->fields = list_make1(makeNode(A_Star));
allColumns->location = -1;
selectTarget->name = NULL;
selectTarget->indirection = NIL;
selectTarget->val = (Node *) allColumns;
selectTarget->location = -1;
selectStmt->targetList = list_make1(selectTarget);
selectStmt->fromClause = list_make1(copyObject(copyStatement->relation));
SelectStmt *selectStmt = CitusCopySelect(copyStatement);
/* replace original statement */
copyStatement = copyObject(copyStatement);
@ -2837,6 +2825,53 @@ ProcessCopyStmt(CopyStmt *copyStatement, char *completionTag, const char *queryS
}
/*
* CitusCopySelect generates a SelectStmt such that table may be replaced in
* "COPY table FROM" for an equivalent result.
*/
static SelectStmt *
CitusCopySelect(CopyStmt *copyStatement)
{
SelectStmt *selectStmt = makeNode(SelectStmt);
selectStmt->fromClause = list_make1(copyObject(copyStatement->relation));
Relation distributedRelation = heap_openrv(copyStatement->relation, AccessShareLock);
TupleDesc tupleDescriptor = RelationGetDescr(distributedRelation);
List *targetList = NIL;
for (int i = 0; i < tupleDescriptor->natts; i++)
{
Form_pg_attribute attr = &tupleDescriptor->attrs[i];
if (attr->attisdropped
#if PG_VERSION_NUM >= PG_VERSION_12
|| attr->attgenerated
#endif
)
{
continue;
}
ColumnRef *column = makeNode(ColumnRef);
column->fields = list_make1(makeString(pstrdup(attr->attname.data)));
column->location = -1;
ResTarget *selectTarget = makeNode(ResTarget);
selectTarget->name = NULL;
selectTarget->indirection = NIL;
selectTarget->val = (Node *) column;
selectTarget->location = -1;
targetList = lappend(targetList, selectTarget);
}
heap_close(distributedRelation, NoLock);
selectStmt->targetList = targetList;
return selectStmt;
}
/*
* CitusCopyTo runs a COPY .. TO STDOUT command on each shard to do a full
* table dump.
@ -3061,6 +3096,10 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
{
if (TupleDescAttr(tupDesc, i)->attisdropped)
continue;
#if PG_VERSION_NUM >= PG_VERSION_12
if (TupleDescAttr(tupDesc, i)->attgenerated)
continue;
#endif
attnums = lappend_int(attnums, i + 1);
}
}
@ -3085,6 +3124,14 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
continue;
if (namestrcmp(&(att->attname), name) == 0)
{
#if PG_VERSION_NUM >= PG_VERSION_12
if (att->attgenerated)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("column \"%s\" is a generated column",
name),
errdetail("Generated columns cannot be used in COPY.")));
#endif
attnum = att->attnum;
break;
}

View File

@ -38,11 +38,13 @@
#include "nodes/makefuncs.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "parser/scansup.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc_tables.h"
#include "utils/guc.h"
#include "utils/rel.h"
#include "utils/varlena.h"
#include "utils/syscache.h"
static const char * ExtractEncryptedPassword(Oid roleOid);
@ -410,7 +412,7 @@ MakeVariableSetStmt(const char *config)
VariableSetStmt *variableSetStmt = makeNode(VariableSetStmt);
variableSetStmt->kind = VAR_SET_VALUE;
variableSetStmt->name = name;
variableSetStmt->args = list_make1(MakeSetStatementArgument(name, value));
variableSetStmt->args = MakeSetStatementArguments(name, value);
return variableSetStmt;
}
@ -624,15 +626,15 @@ GetRoleNameFromDbRoleSetting(HeapTuple tuple, TupleDesc DbRoleSettingDescription
/*
* MakeSetStatementArgs parses a configuraton value and creates an A_Const
* with an appropriate type.
* MakeSetStatementArgs parses a configuraton value and creates an List of A_Const
* Nodes with appropriate types.
*
* The allowed A_Const types are Integer, Float, and String.
*/
Node *
MakeSetStatementArgument(char *configurationName, char *configurationValue)
List *
MakeSetStatementArguments(char *configurationName, char *configurationValue)
{
Node *arg = NULL;
List *args = NIL;
char **key = &configurationName;
/* Perform a lookup on GUC variables to find the config type and units.
@ -668,13 +670,15 @@ MakeSetStatementArgument(char *configurationName, char *configurationValue)
int intValue;
parse_int(configurationValue, &intValue,
(*matchingConfig)->flags, NULL);
arg = makeIntConst(intValue, -1);
Node *arg = makeIntConst(intValue, -1);
args = lappend(args, arg);
break;
}
case PGC_REAL:
{
arg = makeFloatConst(configurationValue, -1);
Node *arg = makeFloatConst(configurationValue, -1);
args = lappend(args, arg);
break;
}
@ -682,7 +686,25 @@ MakeSetStatementArgument(char *configurationName, char *configurationValue)
case PGC_STRING:
case PGC_ENUM:
{
arg = makeStringConst(configurationValue, -1);
List *configurationList = NIL;
if ((*matchingConfig)->flags & GUC_LIST_INPUT)
{
char *configurationValueCopy = pstrdup(configurationValue);
SplitIdentifierString(configurationValueCopy, ',',
&configurationList);
}
else
{
configurationList = list_make1(configurationValue);
}
char *configuration = NULL;
foreach_ptr(configuration, configurationList)
{
Node *arg = makeStringConst(configuration, -1);
args = lappend(args, arg);
}
break;
}
@ -696,9 +718,10 @@ MakeSetStatementArgument(char *configurationName, char *configurationValue)
}
else
{
arg = makeStringConst(configurationValue, -1);
Node *arg = makeStringConst(configurationValue, -1);
args = lappend(args, arg);
}
return (Node *) arg;
return args;
}

View File

@ -127,7 +127,8 @@ PostprocessVariableSetStmt(VariableSetStmt *setStmt, const char *setStmtString)
/* haven't seen any SET stmts so far in this (sub-)xact: initialize StringInfo */
if (activeSetStmts == NULL)
{
MemoryContext old_context = MemoryContextSwitchTo(CurTransactionContext);
/* see comments in PushSubXact on why we allocate this in TopTransactionContext */
MemoryContext old_context = MemoryContextSwitchTo(TopTransactionContext);
activeSetStmts = makeStringInfo();
MemoryContextSwitchTo(old_context);
}

View File

@ -41,7 +41,7 @@
#include "utils/memutils.h"
int NodeConnectionTimeout = 5000;
int NodeConnectionTimeout = 30000;
int MaxCachedConnectionsPerWorker = 1;
HTAB *ConnectionHash = NULL;
@ -193,7 +193,16 @@ GetNodeConnection(uint32 flags, const char *hostname, int32 port)
MultiConnection *
StartNodeConnection(uint32 flags, const char *hostname, int32 port)
{
return StartNodeUserDatabaseConnection(flags, hostname, port, NULL, NULL);
MultiConnection *connection = StartNodeUserDatabaseConnection(flags, hostname, port,
NULL, NULL);
/*
* connection can only be NULL for optional connections, which we don't
* support in this codepath.
*/
Assert((flags & OPTIONAL_CONNECTION) == 0);
Assert(connection != NULL);
return connection;
}
@ -209,6 +218,13 @@ GetNodeUserDatabaseConnection(uint32 flags, const char *hostname, int32 port,
MultiConnection *connection = StartNodeUserDatabaseConnection(flags, hostname, port,
user, database);
/*
* connection can only be NULL for optional connections, which we don't
* support in this codepath.
*/
Assert((flags & OPTIONAL_CONNECTION) == 0);
Assert(connection != NULL);
FinishConnectionEstablishment(connection);
return connection;
@ -236,6 +252,13 @@ StartWorkerListConnections(List *workerNodeList, uint32 flags, const char *user,
nodeName, nodePort,
user, database);
/*
* connection can only be NULL for optional connections, which we don't
* support in this codepath.
*/
Assert((flags & OPTIONAL_CONNECTION) == 0);
Assert(connection != NULL);
connectionList = lappend(connectionList, connection);
}

View File

@ -294,6 +294,13 @@ StartPlacementListConnection(uint32 flags, List *placementAccessList,
chosenConnection = StartNodeUserDatabaseConnection(flags, nodeName, nodePort,
userName, NULL);
/*
* chosenConnection can only be NULL for optional connections, which we
* don't support in this codepath.
*/
Assert((flags & OPTIONAL_CONNECTION) == 0);
Assert(chosenConnection != NULL);
if ((flags & CONNECTION_PER_PLACEMENT) &&
ConnectionAccessedDifferentPlacement(chosenConnection, placement))
{
@ -314,6 +321,13 @@ StartPlacementListConnection(uint32 flags, List *placementAccessList,
nodeName, nodePort,
userName, NULL);
/*
* chosenConnection can only be NULL for optional connections,
* which we don't support in this codepath.
*/
Assert((flags & OPTIONAL_CONNECTION) == 0);
Assert(chosenConnection != NULL);
Assert(!ConnectionAccessedDifferentPlacement(chosenConnection, placement));
}
}

View File

@ -56,5 +56,5 @@ QualifyVarSetCurrent(VariableSetStmt *setStmt)
char *configValue = GetConfigOptionByName(configurationName, NULL, false);
setStmt->kind = VAR_SET_VALUE;
setStmt->args = list_make1(MakeSetStatementArgument(configurationName, configValue));
setStmt->args = list_make1(MakeSetStatementArguments(configurationName, configValue));
}

View File

@ -970,6 +970,7 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
int ncolumns;
char **real_colnames;
bool changed_any;
bool has_anonymous;
int noldcolumns;
int i;
int j;
@ -1057,6 +1058,7 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
*/
noldcolumns = list_length(rte->eref->colnames);
changed_any = false;
has_anonymous = false;
j = 0;
for (i = 0; i < ncolumns; i++)
{
@ -1094,6 +1096,13 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
/* Remember if any assigned aliases differ from "real" name */
if (!changed_any && strcmp(colname, real_colname) != 0)
changed_any = true;
/*
* Remember if there is a reference to an anonymous column as named by
* char * FigureColname(Node *node)
*/
if (!has_anonymous && strcmp(real_colname, "?column?") == 0)
has_anonymous = true;
}
/*
@ -1123,7 +1132,7 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
else if (rte->alias && rte->alias->colnames != NIL)
colinfo->printaliases = true;
else
colinfo->printaliases = changed_any;
colinfo->printaliases = changed_any || has_anonymous;
}
/*

View File

@ -970,6 +970,7 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
int ncolumns;
char **real_colnames;
bool changed_any;
bool has_anonymous;
int noldcolumns;
int i;
int j;
@ -1057,6 +1058,7 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
*/
noldcolumns = list_length(rte->eref->colnames);
changed_any = false;
has_anonymous = false;
j = 0;
for (i = 0; i < ncolumns; i++)
{
@ -1094,6 +1096,13 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
/* Remember if any assigned aliases differ from "real" name */
if (!changed_any && strcmp(colname, real_colname) != 0)
changed_any = true;
/*
* Remember if there is a reference to an anonymous column as named by
* char * FigureColname(Node *node)
*/
if (!has_anonymous && strcmp(real_colname, "?column?") == 0)
has_anonymous = true;
}
/*
@ -1123,7 +1132,7 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
else if (rte->alias && rte->alias->colnames != NIL)
colinfo->printaliases = true;
else
colinfo->printaliases = changed_any;
colinfo->printaliases = changed_any || has_anonymous;
}
/*

View File

@ -208,7 +208,7 @@ typedef struct DistributedExecution
* Flag to indiciate that the set of connections we are interested
* in has changed and waitEventSet needs to be rebuilt.
*/
bool connectionSetChanged;
bool rebuildWaitEventSet;
/*
* Flag to indiciate that the set of wait events we are interested
@ -1064,7 +1064,7 @@ CreateDistributedExecution(RowModifyLevel modLevel, List *taskList,
execution->raiseInterrupts = true;
execution->connectionSetChanged = false;
execution->rebuildWaitEventSet = false;
execution->waitFlagsChanged = false;
execution->jobIdList = jobIdList;
@ -2008,6 +2008,7 @@ FindOrCreateWorkerSession(WorkerPool *workerPool, MultiConnection *connection)
session->connection = connection;
session->workerPool = workerPool;
session->commandsSent = 0;
dlist_init(&session->pendingTaskQueue);
dlist_init(&session->readyTaskQueue);
@ -2142,7 +2143,7 @@ RunDistributedExecution(DistributedExecution *execution)
int eventSetSize = GetEventSetSize(execution->sessionList);
/* always (re)build the wait event set the first time */
execution->connectionSetChanged = true;
execution->rebuildWaitEventSet = true;
while (execution->unfinishedTaskCount > 0 && !cancellationReceived)
{
@ -2154,7 +2155,7 @@ RunDistributedExecution(DistributedExecution *execution)
ManageWorkerPool(workerPool);
}
if (execution->connectionSetChanged)
if (execution->rebuildWaitEventSet)
{
if (events != NULL)
{
@ -2236,7 +2237,7 @@ RebuildWaitEventSet(DistributedExecution *execution)
}
execution->waitEventSet = BuildWaitEventSet(execution->sessionList);
execution->connectionSetChanged = false;
execution->rebuildWaitEventSet = false;
execution->waitFlagsChanged = false;
return GetEventSetSize(execution->sessionList);
@ -2482,7 +2483,7 @@ ManageWorkerPool(WorkerPool *workerPool)
}
INSTR_TIME_SET_CURRENT(workerPool->lastConnectionOpenTime);
execution->connectionSetChanged = true;
execution->rebuildWaitEventSet = true;
}
@ -2751,7 +2752,15 @@ ConnectionStateMachine(WorkerSession *session)
break;
}
int beforePollSocket = PQsocket(connection->pgConn);
PostgresPollingStatusType pollMode = PQconnectPoll(connection->pgConn);
if (beforePollSocket != PQsocket(connection->pgConn))
{
/* rebuild the wait events if PQconnectPoll() changed the socket */
execution->rebuildWaitEventSet = true;
}
if (pollMode == PGRES_POLLING_FAILED)
{
connection->connectionState = MULTI_CONNECTION_FAILED;
@ -2759,10 +2768,16 @@ ConnectionStateMachine(WorkerSession *session)
else if (pollMode == PGRES_POLLING_READING)
{
UpdateConnectionWaitFlags(session, WL_SOCKET_READABLE);
/* we should have a valid socket */
Assert(PQsocket(connection->pgConn) != -1);
}
else if (pollMode == PGRES_POLLING_WRITING)
{
UpdateConnectionWaitFlags(session, WL_SOCKET_WRITEABLE);
/* we should have a valid socket */
Assert(PQsocket(connection->pgConn) != -1);
}
else
{
@ -2771,6 +2786,9 @@ ConnectionStateMachine(WorkerSession *session)
WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE);
connection->connectionState = MULTI_CONNECTION_CONNECTED;
/* we should have a valid socket */
Assert(PQsocket(connection->pgConn) != -1);
}
break;
@ -2855,7 +2873,7 @@ ConnectionStateMachine(WorkerSession *session)
ShutdownConnection(connection);
/* remove connection from wait event set */
execution->connectionSetChanged = true;
execution->rebuildWaitEventSet = true;
/*
* Reset the transaction state machine since CloseConnection()

View File

@ -468,29 +468,19 @@ ExtractLocalAndRemoteTasks(bool readOnly, List *taskList, List **localTaskList,
/* either the local or the remote should be non-nil */
Assert(!(localTaskPlacementList == NIL && remoteTaskPlacementList == NIL));
if (list_length(task->taskPlacementList) == 1)
if (localTaskPlacementList == NIL)
{
/*
* At this point, the task has a single placement (e.g,. anchor shard
* is distributed table's shard). So, it is either added to local or
* remote taskList.
*/
if (localTaskPlacementList == NIL)
{
*remoteTaskList = lappend(*remoteTaskList, task);
}
else
{
*localTaskList = lappend(*localTaskList, task);
}
*remoteTaskList = lappend(*remoteTaskList, task);
}
else if (remoteTaskPlacementList == NIL)
{
*localTaskList = lappend(*localTaskList, task);
}
else
{
/*
* At this point, we're dealing with reference tables or intermediate
* results where the task has placements on both local and remote
* nodes. We always prefer to use local placement, and require remote
* placements only for modifications.
* At this point, we're dealing with a task that has placements on both
* local and remote nodes.
*/
task->partiallyLocalOrRemote = true;
@ -505,6 +495,8 @@ ExtractLocalAndRemoteTasks(bool readOnly, List *taskList, List **localTaskList,
}
else
{
/* since shard replication factor > 1, we should have at least 1 remote task */
Assert(remoteTaskPlacementList != NIL);
Task *remoteTask = copyObject(task);
remoteTask->taskPlacementList = remoteTaskPlacementList;

View File

@ -150,6 +150,13 @@ MultiClientConnectStart(const char *nodeName, uint32 nodePort, const char *nodeD
MultiConnection *connection = StartNodeUserDatabaseConnection(connectionFlags,
nodeName, nodePort,
userName, nodeDatabase);
/*
* connection can only be NULL for optional connections, which we don't
* support in this codepath.
*/
Assert((connectionFlags & OPTIONAL_CONNECTION) == 0);
Assert(connection != NULL);
ConnStatusType connStatusType = PQstatus(connection->pgConn);
/*

View File

@ -2423,13 +2423,13 @@ CurrentUserName(void)
/*
* LookupTypeOid returns the Oid of the "pg_catalog.{typeNameString}" type, or
* LookupTypeOid returns the Oid of the "{schemaNameSting}.{typeNameString}" type, or
* InvalidOid if it does not exist.
*/
static Oid
LookupTypeOid(char *typeNameString)
Oid
LookupTypeOid(char *schemaNameSting, char *typeNameString)
{
Value *schemaName = makeString("pg_catalog");
Value *schemaName = makeString(schemaNameSting);
Value *typeName = makeString(typeNameString);
List *qualifiedName = list_make2(schemaName, typeName);
TypeName *enumTypeName = makeTypeNameFromNameList(qualifiedName);
@ -2461,7 +2461,7 @@ LookupTypeOid(char *typeNameString)
static Oid
LookupStringEnumValueId(char *enumName, char *valueName)
{
Oid enumTypeId = LookupTypeOid(enumName);
Oid enumTypeId = LookupTypeOid("pg_catalog", enumName);
if (enumTypeId == InvalidOid)
{

View File

@ -124,7 +124,6 @@ static PlannerRestrictionContext * CurrentPlannerRestrictionContext(void);
static void PopPlannerRestrictionContext(void);
static void ResetPlannerRestrictionContext(
PlannerRestrictionContext *plannerRestrictionContext);
static bool HasUnresolvedExternParamsWalker(Node *expression, ParamListInfo boundParams);
static bool IsLocalReferenceTableJoin(Query *parse, List *rangeTableList);
static bool QueryIsNotSimpleSelect(Node *node);
static void UpdateReferenceTablesWithShard(List *rangeTableList);
@ -2242,7 +2241,7 @@ ResetPlannerRestrictionContext(PlannerRestrictionContext *plannerRestrictionCont
* has external parameters that are not contained in boundParams, false
* otherwise.
*/
static bool
bool
HasUnresolvedExternParamsWalker(Node *expression, ParamListInfo boundParams)
{
if (expression == NULL)

View File

@ -314,12 +314,10 @@ TryToDelegateFunctionCall(DistributedPlanningContext *planContext)
if (partitionValue->consttype != partitionColumn->vartype)
{
CopyCoercionData coercionData;
ConversionPathForTypes(partitionValue->consttype, partitionColumn->vartype,
&coercionData);
partitionValueDatum = CoerceColumnValue(partitionValueDatum, &coercionData);
bool missingOk = false;
partitionValue =
TransformPartitionRestrictionValue(partitionColumn, partitionValue,
missingOk);
}
shardInterval = FindShardInterval(partitionValueDatum, distTable);

View File

@ -39,6 +39,7 @@
#include "distributed/multi_logical_planner.h"
#include "distributed/multi_physical_planner.h"
#include "distributed/pg_dist_partition.h"
#include "distributed/tdigest_extension.h"
#include "distributed/worker_protocol.h"
#include "distributed/version_compat.h"
#include "nodes/makefuncs.h"
@ -61,6 +62,8 @@
#include "utils/rel.h"
#include "utils/syscache.h"
#define StartsWith(msg, prefix) \
(strncmp(msg, prefix, strlen(prefix)) == 0)
/* Config variable managed via guc.c */
int LimitClauseRowFetchCount = -1; /* number of rows to fetch from each task */
@ -1951,6 +1954,131 @@ MasterAggregateExpression(Aggref *originalAggregate,
newMasterExpression = (Expr *) unionAggregate;
}
else if (aggregateType == AGGREGATE_TDIGEST_COMBINE ||
aggregateType == AGGREGATE_TDIGEST_ADD_DOUBLE)
{
/* tdigest of column */
Oid tdigestType = TDigestExtensionTypeOid(); /* tdigest type */
Oid unionFunctionId = TDigestExtensionAggTDigest1();
int32 tdigestReturnTypeMod = exprTypmod((Node *) originalAggregate);
Oid tdigestTypeCollationId = exprCollation((Node *) originalAggregate);
/* create first argument for tdigest_precentile(tdigest, double) */
Var *tdigestColumn = makeVar(masterTableId, walkerContext->columnId, tdigestType,
tdigestReturnTypeMod, tdigestTypeCollationId,
columnLevelsUp);
TargetEntry *tdigestTargetEntry = makeTargetEntry((Expr *) tdigestColumn,
argumentId,
NULL, false);
walkerContext->columnId++;
/* construct the master tdigest(tdigest) expression */
Aggref *unionAggregate = makeNode(Aggref);
unionAggregate->aggfnoid = unionFunctionId;
unionAggregate->aggtype = originalAggregate->aggtype;
unionAggregate->args = list_make1(tdigestTargetEntry);
unionAggregate->aggkind = AGGKIND_NORMAL;
unionAggregate->aggfilter = NULL;
unionAggregate->aggtranstype = InvalidOid;
unionAggregate->aggargtypes = list_make1_oid(tdigestType);
unionAggregate->aggsplit = AGGSPLIT_SIMPLE;
newMasterExpression = (Expr *) unionAggregate;
}
else if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLEARRAY ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLEARRAY)
{
/* tdigest of column */
Oid tdigestType = TDigestExtensionTypeOid();
Oid unionFunctionId = InvalidOid;
if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLE)
{
unionFunctionId = TDigestExtensionAggTDigestPercentile2();
}
else if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLEARRAY)
{
unionFunctionId = TDigestExtensionAggTDigestPercentile2a();
}
else if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLE)
{
unionFunctionId = TDigestExtensionAggTDigestPercentileOf2();
}
else if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLEARRAY)
{
unionFunctionId = TDigestExtensionAggTDigestPercentileOf2a();
}
Assert(OidIsValid(unionFunctionId));
int32 tdigestReturnTypeMod = exprTypmod((Node *) originalAggregate);
Oid tdigestTypeCollationId = exprCollation((Node *) originalAggregate);
/* create first argument for tdigest_precentile(tdigest, double) */
Var *tdigestColumn = makeVar(masterTableId, walkerContext->columnId, tdigestType,
tdigestReturnTypeMod, tdigestTypeCollationId,
columnLevelsUp);
TargetEntry *tdigestTargetEntry = makeTargetEntry((Expr *) tdigestColumn,
argumentId, NULL, false);
walkerContext->columnId++;
/* construct the master tdigest_precentile(tdigest, double) expression */
Aggref *unionAggregate = makeNode(Aggref);
unionAggregate->aggfnoid = unionFunctionId;
unionAggregate->aggtype = originalAggregate->aggtype;
unionAggregate->args = list_make2(
tdigestTargetEntry,
list_nth(originalAggregate->args, 2));
unionAggregate->aggkind = AGGKIND_NORMAL;
unionAggregate->aggfilter = NULL;
unionAggregate->aggtranstype = InvalidOid;
unionAggregate->aggargtypes = list_make2_oid(
tdigestType,
list_nth_oid(originalAggregate->aggargtypes, 2));
unionAggregate->aggsplit = AGGSPLIT_SIMPLE;
newMasterExpression = (Expr *) unionAggregate;
}
else if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLEARRAY ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLEARRAY)
{
/* tdigest of column */
Oid tdigestType = TDigestExtensionTypeOid();
/* These functions already will combine the tdigest arguments returned */
Oid unionFunctionId = originalAggregate->aggfnoid;
int32 tdigestReturnTypeMod = exprTypmod((Node *) originalAggregate);
Oid tdigestTypeCollationId = exprCollation((Node *) originalAggregate);
/* create first argument for tdigest_precentile(tdigest, double) */
Var *tdigestColumn = makeVar(masterTableId, walkerContext->columnId, tdigestType,
tdigestReturnTypeMod, tdigestTypeCollationId,
columnLevelsUp);
TargetEntry *tdigestTargetEntry = makeTargetEntry((Expr *) tdigestColumn,
argumentId, NULL, false);
walkerContext->columnId++;
/* construct the master tdigest_precentile(tdigest, double) expression */
Aggref *unionAggregate = makeNode(Aggref);
unionAggregate->aggfnoid = unionFunctionId;
unionAggregate->aggtype = originalAggregate->aggtype;
unionAggregate->args = list_make2(
tdigestTargetEntry,
list_nth(originalAggregate->args, 1));
unionAggregate->aggkind = AGGKIND_NORMAL;
unionAggregate->aggfilter = NULL;
unionAggregate->aggtranstype = InvalidOid;
unionAggregate->aggargtypes = list_make2_oid(
tdigestType,
list_nth_oid(originalAggregate->aggargtypes, 1));
unionAggregate->aggsplit = AGGSPLIT_SIMPLE;
newMasterExpression = (Expr *) unionAggregate;
}
else if (aggregateType == AGGREGATE_CUSTOM_COMBINE)
{
HeapTuple aggTuple =
@ -3079,6 +3207,71 @@ WorkerAggregateExpressionList(Aggref *originalAggregate,
workerAggregateList = lappend(workerAggregateList, sumAggregate);
workerAggregateList = lappend(workerAggregateList, countAggregate);
}
else if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLEARRAY ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLEARRAY)
{
/*
* The original query has an aggregate in the form of either
* - tdigest_percentile(column, compression, quantile)
* - tdigest_percentile(column, compression, quantile[])
* - tdigest_percentile_of(column, compression, value)
* - tdigest_percentile_of(column, compression, value[])
*
* We are creating the worker part of this query by creating a
* - tdigest(column, compression)
*
* One could see we are passing argument 0 and argument 1 from the original query
* in here. This corresponds with the list_nth calls in the args and aggargstypes
* list construction. The tdigest function and type are read from the catalog.
*/
Aggref *newWorkerAggregate = copyObject(originalAggregate);
newWorkerAggregate->aggfnoid = TDigestExtensionAggTDigest2();
newWorkerAggregate->aggtype = TDigestExtensionTypeOid();
newWorkerAggregate->args = list_make2(
list_nth(newWorkerAggregate->args, 0),
list_nth(newWorkerAggregate->args, 1));
newWorkerAggregate->aggkind = AGGKIND_NORMAL;
newWorkerAggregate->aggtranstype = InvalidOid;
newWorkerAggregate->aggargtypes = list_make2_oid(
list_nth_oid(newWorkerAggregate->aggargtypes, 0),
list_nth_oid(newWorkerAggregate->aggargtypes, 1));
newWorkerAggregate->aggsplit = AGGSPLIT_SIMPLE;
workerAggregateList = lappend(workerAggregateList, newWorkerAggregate);
}
else if (aggregateType == AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLEARRAY ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLE ||
aggregateType == AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLEARRAY)
{
/*
* The original query has an aggregate in the form of either
* - tdigest_percentile(tdigest, quantile)
* - tdigest_percentile(tdigest, quantile[])
* - tdigest_percentile_of(tdigest, value)
* - tdigest_percentile_of(tdigest, value[])
*
* We are creating the worker part of this query by creating a
* - tdigest(tdigest)
*
* One could see we are passing argument 0 from the original query in here. This
* corresponds with the list_nth calls in the args and aggargstypes list
* construction. The tdigest function and type are read from the catalog.
*/
Aggref *newWorkerAggregate = copyObject(originalAggregate);
newWorkerAggregate->aggfnoid = TDigestExtensionAggTDigest1();
newWorkerAggregate->aggtype = TDigestExtensionTypeOid();
newWorkerAggregate->args = list_make1(list_nth(newWorkerAggregate->args, 0));
newWorkerAggregate->aggkind = AGGKIND_NORMAL;
newWorkerAggregate->aggtranstype = InvalidOid;
newWorkerAggregate->aggargtypes = list_make1_oid(
list_nth_oid(newWorkerAggregate->aggargtypes, 0));
newWorkerAggregate->aggsplit = AGGSPLIT_SIMPLE;
workerAggregateList = lappend(workerAggregateList, newWorkerAggregate);
}
else if (aggregateType == AGGREGATE_CUSTOM_COMBINE)
{
HeapTuple aggTuple =
@ -3178,6 +3371,66 @@ GetAggregateType(Aggref *aggregateExpression)
}
}
/*
* All functions from github.com/tvondra/tdigest start with the "tdigest" prefix.
* Since it requires lookups of function names in a schema we would like to only
* perform these checks if there is some chance it will actually result in a positive
* hit.
*/
if (StartsWith(aggregateProcName, "tdigest"))
{
if (aggFunctionId == TDigestExtensionAggTDigest1())
{
return AGGREGATE_TDIGEST_COMBINE;
}
if (aggFunctionId == TDigestExtensionAggTDigest2())
{
return AGGREGATE_TDIGEST_ADD_DOUBLE;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentile3())
{
return AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLE;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentile3a())
{
return AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLEARRAY;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentile2())
{
return AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLE;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentile2a())
{
return AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLEARRAY;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentileOf3())
{
return AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLE;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentileOf3a())
{
return AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLEARRAY;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentileOf2())
{
return AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLE;
}
if (aggFunctionId == TDigestExtensionAggTDigestPercentileOf2a())
{
return AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLEARRAY;
}
}
if (AggregateEnabledCustom(aggregateExpression))
{
return AGGREGATE_CUSTOM_COMBINE;

View File

@ -177,6 +177,20 @@ CitusCustomScanPathPlan(PlannerInfo *root,
{
CitusCustomScanPath *citusPath = (CitusCustomScanPath *) best_path;
/*
* Columns could have been pruned from the target list by the standard planner.
* A situation in which this might happen is a CASE that is proven to be always the
* same causing the other column to become useless;
* CASE WHEN ... <> NULL
* THEN ...
* ELSE ...
* END
* Since nothing is equal to NULL it will always end up in the else branch. The final
* target list the planenr needs from our node is passed in as tlist. By placing that
* as the target list on our scan the internal rows will be projected to this one.
*/
citusPath->remoteScan->scan.plan.targetlist = tlist;
/* clauses might have been added by the planner, need to add them to our scan */
RestrictInfo *restrictInfo = NULL;
List **quals = &citusPath->remoteScan->scan.plan.qual;

View File

@ -95,6 +95,24 @@ bool EnableUniqueJobIds = true;
static List *OperatorCache = NIL;
/* context passed down in AddAnyValueAggregates mutator */
typedef struct AddAnyValueAggregatesContext
{
/* SortGroupClauses corresponding to the GROUP BY clause */
List *groupClauseList;
/* TargetEntry's to which the GROUP BY clauses refer */
List *groupByTargetEntryList;
/*
* haveNonVarGrouping is true if there are expressions in the
* GROUP BY target entries. We use this as an optimisation to
* skip expensive checks when possible.
*/
bool haveNonVarGrouping;
} AddAnyValueAggregatesContext;
/* Local functions forward declarations for job creation */
static Job * BuildJobTree(MultiTreeRoot *multiTree);
static MultiNode * LeftMostNode(MultiTreeRoot *multiTree);
@ -105,6 +123,7 @@ static Query * BuildReduceQuery(MultiExtendedOp *extendedOpNode, List *dependent
static List * BaseRangeTableList(MultiNode *multiNode);
static List * QueryTargetList(MultiNode *multiNode);
static List * TargetEntryList(List *expressionList);
static Node * AddAnyValueAggregates(Node *node, AddAnyValueAggregatesContext *context);
static List * QueryGroupClauseList(MultiNode *multiNode);
static List * QuerySelectClauseList(MultiNode *multiNode);
static List * QueryJoinClauseList(MultiNode *multiNode);
@ -696,13 +715,11 @@ BuildJobQuery(MultiNode *multiNode, List *dependentJobList)
*/
if (groupClauseList != NIL && isRepartitionJoin)
{
targetList = (List *) expression_tree_mutator((Node *) targetList,
AddAnyValueAggregates,
groupClauseList);
targetList = (List *) WrapUngroupedVarsInAnyValueAggregate(
(Node *) targetList, groupClauseList, targetList, true);
havingQual = expression_tree_mutator((Node *) havingQual,
AddAnyValueAggregates,
groupClauseList);
havingQual = WrapUngroupedVarsInAnyValueAggregate(
(Node *) havingQual, groupClauseList, targetList, false);
}
/*
@ -974,23 +991,116 @@ TargetEntryList(List *expressionList)
/*
* AddAnyValueAggregates wraps all vars that do not appear in the GROUP BY
* clause or are inside an aggregate function in an any_value aggregate
* function. This is needed for repartition joins because primary keys are not
* present on intermediate tables.
* WrapUngroupedVarsInAnyValueAggregate finds Var nodes in the expression
* that do not refer to any GROUP BY column and wraps them in an any_value
* aggregate. These columns are allowed when the GROUP BY is on a primary
* key of a relation, but not if we wrap the relation in a subquery.
* However, since we still know the value is unique, any_value gives the
* right result.
*/
Node *
AddAnyValueAggregates(Node *node, void *context)
WrapUngroupedVarsInAnyValueAggregate(Node *expression, List *groupClauseList,
List *targetList, bool checkExpressionEquality)
{
if (expression == NULL)
{
return NULL;
}
AddAnyValueAggregatesContext context;
context.groupClauseList = groupClauseList;
context.groupByTargetEntryList = GroupTargetEntryList(groupClauseList, targetList);
context.haveNonVarGrouping = false;
if (checkExpressionEquality)
{
/*
* If the GROUP BY contains non-Var expressions, we need to do an expensive
* subexpression equality check.
*/
TargetEntry *targetEntry = NULL;
foreach_ptr(targetEntry, context.groupByTargetEntryList)
{
if (!IsA(targetEntry->expr, Var))
{
context.haveNonVarGrouping = true;
break;
}
}
}
/* put the result in the same memory context */
MemoryContext nodeContext = GetMemoryChunkContext(expression);
MemoryContext oldContext = MemoryContextSwitchTo(nodeContext);
Node *result = expression_tree_mutator(expression, AddAnyValueAggregates,
&context);
MemoryContextSwitchTo(oldContext);
return result;
}
/*
* AddAnyValueAggregates wraps all vars that do not appear in the GROUP BY
* clause or are inside an aggregate function in an any_value aggregate
* function. This is needed because postgres allows columns that are not
* in the GROUP BY to appear on the target list as long as the primary key
* of the table is in the GROUP BY, but we sometimes wrap the join tree
* in a subquery in which case the primary key information is lost.
*
* This function copies parts of the node tree, but may contain references
* to the original node tree.
*
* The implementation is derived from / inspired by
* check_ungrouped_columns_walker.
*/
static Node *
AddAnyValueAggregates(Node *node, AddAnyValueAggregatesContext *context)
{
List *groupClauseList = context;
if (node == NULL)
{
return node;
}
if (IsA(node, Var))
if (IsA(node, Aggref) || IsA(node, GroupingFunc))
{
/* any column is allowed to appear in an aggregate or grouping */
return node;
}
else if (IsA(node, Var))
{
Var *var = (Var *) node;
/*
* Check whether this Var appears in the GROUP BY.
*/
TargetEntry *groupByTargetEntry = NULL;
foreach_ptr(groupByTargetEntry, context->groupByTargetEntryList)
{
if (!IsA(groupByTargetEntry->expr, Var))
{
continue;
}
Var *groupByVar = (Var *) groupByTargetEntry->expr;
/* we should only be doing this at the top level of the query */
Assert(groupByVar->varlevelsup == 0);
if (var->varno == groupByVar->varno &&
var->varattno == groupByVar->varattno)
{
/* this Var is in the GROUP BY, do not wrap it */
return node;
}
}
/*
* We have found a Var that does not appear in the GROUP BY.
* Wrap it in an any_value aggregate.
*/
Aggref *agg = makeNode(Aggref);
agg->aggfnoid = CitusAnyValueFunctionId();
agg->aggtype = var->vartype;
@ -1002,31 +1112,24 @@ AddAnyValueAggregates(Node *node, void *context)
agg->aggcollid = exprCollation((Node *) var);
return (Node *) agg;
}
if (IsA(node, TargetEntry))
else if (context->haveNonVarGrouping)
{
TargetEntry *targetEntry = (TargetEntry *) node;
/*
* Stop searching this part of the tree if the targetEntry is part of
* the group by clause.
* The GROUP BY contains at least one expression. Check whether the
* current expression is equal to one of the GROUP BY expressions.
* Otherwise, continue to descend into subexpressions.
*/
if (targetEntry->ressortgroupref != 0)
TargetEntry *groupByTargetEntry = NULL;
foreach_ptr(groupByTargetEntry, context->groupByTargetEntryList)
{
SortGroupClause *sortGroupClause = NULL;
foreach_ptr(sortGroupClause, groupClauseList)
if (equal(node, groupByTargetEntry->expr))
{
if (sortGroupClause->tleSortGroupRef == targetEntry->ressortgroupref)
{
return node;
}
/* do not descend into mutator, all Vars are safe */
return node;
}
}
}
if (IsA(node, Aggref) || IsA(node, GroupingFunc))
{
return node;
}
return expression_tree_mutator(node, AddAnyValueAggregates, context);
}
@ -2130,12 +2233,29 @@ BuildJobTreeTaskList(Job *jobTree, PlannerRestrictionContext *plannerRestriction
List *assignedSqlTaskList = AssignTaskList(sqlTaskList);
AssignDataFetchDependencies(assignedSqlTaskList);
/* now assign merge task's data fetch dependencies */
/* if the parameters has not been resolved, record it */
job->parametersInJobQueryResolved =
!HasUnresolvedExternParamsWalker((Node *) job->jobQuery, NULL);
/*
* Make final adjustments for the assigned tasks.
*
* First, update SELECT tasks' parameters resolved field.
*
* Second, assign merge task's data fetch dependencies.
*/
foreach(assignedSqlTaskCell, assignedSqlTaskList)
{
Task *assignedSqlTask = (Task *) lfirst(assignedSqlTaskCell);
List *assignedMergeTaskList = FindDependentMergeTaskList(assignedSqlTask);
/* we don't support parameters in the physical planner */
if (assignedSqlTask->taskType == SELECT_TASK)
{
assignedSqlTask->parametersInQueryStringResolved =
job->parametersInJobQueryResolved;
}
List *assignedMergeTaskList = FindDependentMergeTaskList(assignedSqlTask);
AssignDataFetchDependencies(assignedMergeTaskList);
}

View File

@ -2317,6 +2317,20 @@ TargetShardIntervalForFastPathQuery(Query *query, bool *isMultiShardQuery,
if (inputDistributionKeyValue && !inputDistributionKeyValue->constisnull)
{
CitusTableCacheEntry *cache = GetCitusTableCacheEntry(relationId);
Var *distributionKey = cache->partitionColumn;
/*
* We currently don't allow implicitly coerced values to be handled by fast-
* path planner. Still, let's be defensive for any future changes..
*/
if (inputDistributionKeyValue->consttype != distributionKey->vartype)
{
bool missingOk = false;
inputDistributionKeyValue =
TransformPartitionRestrictionValue(distributionKey,
inputDistributionKeyValue, missingOk);
}
ShardInterval *cachedShardInterval =
FindShardInterval(inputDistributionKeyValue->constvalue, cache);
if (cachedShardInterval == NULL)
@ -2638,9 +2652,20 @@ BuildRoutesForInsert(Query *query, DeferredErrorMessage **planningError)
if (partitionMethod == DISTRIBUTE_BY_HASH || partitionMethod ==
DISTRIBUTE_BY_RANGE)
{
Var *distributionKey = cacheEntry->partitionColumn;
/* handle coercions, if fails throw an error */
if (partitionValueConst->consttype != distributionKey->vartype)
{
bool missingOk = false;
partitionValueConst =
TransformPartitionRestrictionValue(distributionKey,
partitionValueConst,
missingOk);
}
Datum partitionValue = partitionValueConst->constvalue;
cacheEntry = GetCitusTableCacheEntry(distributedTableId);
ShardInterval *shardInterval = FindShardInterval(partitionValue, cacheEntry);
if (shardInterval != NULL)
{

View File

@ -1648,15 +1648,15 @@ SubqueryPushdownMultiNodeTree(Query *originalQuery)
*/
if (extendedOpNode->groupClauseList != NIL)
{
extendedOpNode->targetList =
(List *) expression_tree_mutator((Node *) extendedOpNode->targetList,
AddAnyValueAggregates,
extendedOpNode->groupClauseList);
extendedOpNode->targetList = (List *) WrapUngroupedVarsInAnyValueAggregate(
(Node *) extendedOpNode->targetList,
extendedOpNode->groupClauseList,
extendedOpNode->targetList, true);
extendedOpNode->havingQual =
expression_tree_mutator((Node *) extendedOpNode->havingQual,
AddAnyValueAggregates,
extendedOpNode->groupClauseList);
extendedOpNode->havingQual = WrapUngroupedVarsInAnyValueAggregate(
(Node *) extendedOpNode->havingQual,
extendedOpNode->groupClauseList,
extendedOpNode->targetList, false);
}
/*

View File

@ -93,6 +93,7 @@
#include "parser/parse_coerce.h"
#include "utils/arrayaccess.h"
#include "utils/catcache.h"
#include "utils/fmgrprotos.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/ruleutils.h"
@ -255,14 +256,14 @@ static void AddPartitionKeyRestrictionToInstance(ClauseWalkerContext *context,
Const *constantClause);
static bool VarConstOpExprClause(OpExpr *opClause, Var *partitionColumn,
Var **varClause, Const **constantClause);
static Const * TransformPartitionRestrictionValue(Var *partitionColumn,
Const *restrictionValue);
static void AddSAOPartitionKeyRestrictionToInstance(ClauseWalkerContext *context,
ScalarArrayOpExpr *
arrayOperatorExpression);
static bool SAORestrictions(ScalarArrayOpExpr *arrayOperatorExpression,
Var *partitionColumn,
List **requestedRestrictions);
static void ErrorTypesDontMatch(Oid firstType, Oid firstCollId, Oid secondType,
Oid secondCollId);
static bool IsValidHashRestriction(OpExpr *opClause);
static void AddHashRestrictionToInstance(ClauseWalkerContext *context, OpExpr *opClause,
Var *varClause, Const *constantClause);
@ -1111,7 +1112,7 @@ AddPartitionKeyRestrictionToInstance(ClauseWalkerContext *context, OpExpr *opCla
{
/* we want our restriction value in terms of the type of the partition column */
constantClause = TransformPartitionRestrictionValue(partitionColumn,
constantClause);
constantClause, true);
if (constantClause == NULL)
{
/* couldn't coerce value, its invalid restriction */
@ -1223,8 +1224,9 @@ AddPartitionKeyRestrictionToInstance(ClauseWalkerContext *context, OpExpr *opCla
* It is conceivable that in some instances this may not be possible,
* in those cases we will simply fail to prune partitions based on this clause.
*/
static Const *
TransformPartitionRestrictionValue(Var *partitionColumn, Const *restrictionValue)
Const *
TransformPartitionRestrictionValue(Var *partitionColumn, Const *restrictionValue,
bool missingOk)
{
Node *transformedValue = coerce_to_target_type(NULL, (Node *) restrictionValue,
restrictionValue->consttype,
@ -1236,6 +1238,13 @@ TransformPartitionRestrictionValue(Var *partitionColumn, Const *restrictionValue
/* if NULL, no implicit coercion is possible between the types */
if (transformedValue == NULL)
{
if (!missingOk)
{
ErrorTypesDontMatch(partitionColumn->vartype, partitionColumn->varcollid,
restrictionValue->consttype,
restrictionValue->constcollid);
}
return NULL;
}
@ -1248,6 +1257,13 @@ TransformPartitionRestrictionValue(Var *partitionColumn, Const *restrictionValue
/* if still not a constant, no immutable coercion matched */
if (!IsA(transformedValue, Const))
{
if (!missingOk)
{
ErrorTypesDontMatch(partitionColumn->vartype, partitionColumn->varcollid,
restrictionValue->consttype,
restrictionValue->constcollid);
}
return NULL;
}
@ -1255,6 +1271,24 @@ TransformPartitionRestrictionValue(Var *partitionColumn, Const *restrictionValue
}
/*
* ErrorTypesDontMatch throws an error explicitly printing the type names.
*/
static void
ErrorTypesDontMatch(Oid firstType, Oid firstCollId, Oid secondType, Oid secondCollId)
{
Datum firstTypename =
DirectFunctionCall1Coll(regtypeout, firstCollId, ObjectIdGetDatum(firstType));
Datum secondTypename =
DirectFunctionCall1Coll(regtypeout, secondCollId, ObjectIdGetDatum(secondType));
ereport(ERROR, (errmsg("Cannot coerce %s to %s",
DatumGetCString(secondTypename),
DatumGetCString(firstTypename))));
}
/*
* IsValidHashRestriction checks whether an operator clause is a valid restriction for hashed column.
*/

View File

@ -0,0 +1,248 @@
/*-------------------------------------------------------------------------
*
* tdigest_extension.c
* Helper functions to get access to tdigest specific data.
*
* Copyright (c) Citus Data, Inc.
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_type.h"
#include "distributed/metadata_cache.h"
#include "distributed/tdigest_extension.h"
#include "parser/parse_func.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
static Oid LookupTDigestFunction(const char *functionName, int argcount, Oid *argtypes);
/*
* TDigestExtensionSchema finds the schema the tdigest extension is installed in. The
* function will return InvalidOid if the extension is not installed.
*/
Oid
TDigestExtensionSchema()
{
ScanKeyData entry[1];
Form_pg_extension extensionForm = NULL;
Oid tdigestExtensionSchema = InvalidOid;
Relation relation = heap_open(ExtensionRelationId, AccessShareLock);
ScanKeyInit(&entry[0],
Anum_pg_extension_extname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum("tdigest"));
SysScanDesc scandesc = systable_beginscan(relation, ExtensionNameIndexId, true,
NULL, 1, entry);
HeapTuple extensionTuple = systable_getnext(scandesc);
/*
* We assume that there can be at most one matching tuple, if no tuple found the
* extension is not installed. The value of InvalidOid will not be changed.
*/
if (HeapTupleIsValid(extensionTuple))
{
extensionForm = (Form_pg_extension) GETSTRUCT(extensionTuple);
tdigestExtensionSchema = extensionForm->extnamespace;
Assert(OidIsValid(tdigestExtensionSchema));
}
systable_endscan(scandesc);
heap_close(relation, AccessShareLock);
return tdigestExtensionSchema;
}
/*
* TDigestExtensionTypeOid performs a lookup for the Oid of the type representing the
* tdigest as installed by the tdigest extension returns InvalidOid if the type cannot be
* found.
*/
Oid
TDigestExtensionTypeOid()
{
Oid tdigestSchemaOid = TDigestExtensionSchema();
if (!OidIsValid(tdigestSchemaOid))
{
return InvalidOid;
}
char *namespaceName = get_namespace_name(tdigestSchemaOid);
return LookupTypeOid(namespaceName, "tdigest");
}
/*
* LookupTDigestFunction is a helper function specifically to lookup functions in the
* namespace/schema where the tdigest extension is installed. This makes the lookup of
* following aggregate functions easier and less repetitive.
*/
static Oid
LookupTDigestFunction(const char *functionName, int argcount, Oid *argtypes)
{
Oid tdigestSchemaOid = TDigestExtensionSchema();
if (!OidIsValid(tdigestSchemaOid))
{
return InvalidOid;
}
char *namespaceName = get_namespace_name(tdigestSchemaOid);
return LookupFuncName(
list_make2(makeString(namespaceName), makeString(pstrdup(functionName))),
argcount, argtypes, true);
}
/*
* TDigestExtensionAggTDigest1 performs a lookup for the Oid of the tdigest aggregate;
* tdigest(tdigest)
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigest1()
{
return LookupTDigestFunction("tdigest", 1, (Oid[]) { TDigestExtensionTypeOid() });
}
/*
* TDigestExtensionAggTDigest2 performs a lookup for the Oid of the tdigest aggregate;
* tdigest(value double precision, compression int)
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigest2()
{
return LookupTDigestFunction("tdigest", 2, (Oid[]) { FLOAT8OID, INT4OID });
}
/*
* TDigestExtensionAggTDigestPercentile2 performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile(tdigest, double precision)
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentile2()
{
return LookupTDigestFunction("tdigest_percentile", 2,
(Oid[]) { TDigestExtensionTypeOid(), FLOAT8OID });
}
/*
* TDigestExtensionAggTDigestPercentile2a performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile(tdigest, double precision[])
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentile2a(void)
{
return LookupTDigestFunction("tdigest_percentile", 2,
(Oid[]) { TDigestExtensionTypeOid(), FLOAT8ARRAYOID });
}
/*
* TDigestExtensionAggTDigestPercentile3 performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile(double precision, int, double precision)
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentile3()
{
return LookupTDigestFunction("tdigest_percentile", 3,
(Oid[]) { FLOAT8OID, INT4OID, FLOAT8OID });
}
/*
* TDigestExtensionAggTDigestPercentile3a performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile(double precision, int, double precision[])
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentile3a(void)
{
return LookupTDigestFunction("tdigest_percentile", 3,
(Oid[]) { FLOAT8OID, INT4OID, FLOAT8ARRAYOID });
}
/*
* TDigestExtensionAggTDigestPercentileOf2 performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile_of(tdigest, double precision)
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentileOf2()
{
return LookupTDigestFunction("tdigest_percentile_of", 2,
(Oid[]) { TDigestExtensionTypeOid(), FLOAT8OID });
}
/*
* TDigestExtensionAggTDigestPercentileOf2a performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile_of(tdigest, double precision[])
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentileOf2a(void)
{
return LookupTDigestFunction("tdigest_percentile_of", 2,
(Oid[]) { TDigestExtensionTypeOid(), FLOAT8ARRAYOID });
}
/*
* TDigestExtensionAggTDigestPercentileOf3 performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile_of(double precision, int, double precision)
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentileOf3()
{
return LookupTDigestFunction("tdigest_percentile_of", 3,
(Oid[]) { FLOAT8OID, INT4OID, FLOAT8OID });
}
/*
* TDigestExtensionAggTDigestPercentileOf3a performs a lookup for the Oid of the tdigest
* aggregate;
* tdigest_percentile_of(double precision, int, double precision[])
*
* If the aggregate is not found InvalidOid is returned.
*/
Oid
TDigestExtensionAggTDigestPercentileOf3a(void)
{
return LookupTDigestFunction("tdigest_percentile_of", 3,
(Oid[]) { FLOAT8OID, INT4OID, FLOAT8ARRAYOID });
}

View File

@ -450,7 +450,7 @@ RegisterCitusConfigVariables(void)
gettext_noop("Sets the maximum duration to connect to worker nodes."),
NULL,
&NodeConnectionTimeout,
5 * MS_PER_SECOND, 10 * MS, MS_PER_HOUR,
30 * MS_PER_SECOND, 10 * MS, MS_PER_HOUR,
PGC_USERSET,
GUC_UNIT_MS | GUC_STANDARD,
NULL, NULL, NULL);

View File

@ -0,0 +1,2 @@
-- citus--9.2-4--9.2-2
-- this is an empty downgrade path since citus--9.2-2--9.2-4.sql is empty

View File

@ -0,0 +1,30 @@
-- citus--9.3-2--9.2-4
-- this is a downgrade path that will revert the changes made in citus--9.2-4--9.3-2.sql
--
-- 9.3-2 added citus extension owner as a distributed object, if not already in there.
-- However we can not really know if it was a distributed owner prior to 9.3-2.
-- That's why we leave the record in place.
-- Revert the return type to void
DROP FUNCTION pg_catalog.citus_extradata_container(INTERNAL);
CREATE FUNCTION pg_catalog.citus_extradata_container(INTERNAL)
RETURNS void
LANGUAGE C
AS 'MODULE_PATHNAME', $$citus_extradata_container$$;
COMMENT ON FUNCTION pg_catalog.citus_extradata_container(INTERNAL)
IS 'placeholder function to store additional data in postgres node trees';
-- Remove newly introduced functions that are absent in earlier versions
DROP FUNCTION pg_catalog.update_distributed_table_colocation(regclass, text);
DROP FUNCTION pg_catalog.replicate_reference_tables();
DROP FUNCTION pg_catalog.citus_remote_connection_stats(
OUT hostname text,
OUT port int,
OUT database_name text,
OUT connection_count_to_node int);
DROP FUNCTION pg_catalog.worker_create_or_alter_role(
role_name text,
create_role_utility_query text,
alter_role_utility_query text);
DROP FUNCTION pg_catalog.truncate_local_data_after_distributing_table(
function_name regclass);

View File

@ -0,0 +1,56 @@
/*-------------------------------------------------------------------------
*
* xact_stats.c
*
* This file contains functions to provide helper UDFs for testing transaction
* statistics.
*
* Copyright (c) Citus Data, Inc.
*
*-------------------------------------------------------------------------
*/
#include <sys/stat.h>
#include <unistd.h>
#include "postgres.h"
#include "funcapi.h"
#include "libpq-fe.h"
#include "miscadmin.h"
#include "pgstat.h"
static Size MemoryContextTotalSpace(MemoryContext context);
PG_FUNCTION_INFO_V1(top_transaction_context_size);
/*
* top_transaction_context_size returns current size of TopTransactionContext.
*/
Datum
top_transaction_context_size(PG_FUNCTION_ARGS)
{
Size totalSpace = MemoryContextTotalSpace(TopTransactionContext);
PG_RETURN_INT64(totalSpace);
}
/*
* MemoryContextTotalSpace returns total space allocated in context and its children.
*/
static Size
MemoryContextTotalSpace(MemoryContext context)
{
Size totalSpace = 0;
MemoryContextCounters totals = { 0 };
TopTransactionContext->methods->stats(TopTransactionContext, NULL, NULL, &totals);
totalSpace += totals.totalspace;
for (MemoryContext child = context->firstchild;
child != NULL;
child = child->nextchild)
{
totalSpace += MemoryContextTotalSpace(child);
}
return totalSpace;
}

View File

@ -589,7 +589,17 @@ AdjustMaxPreparedTransactions(void)
static void
PushSubXact(SubTransactionId subId)
{
MemoryContext old_context = MemoryContextSwitchTo(CurTransactionContext);
/*
* We need to allocate these in TopTransactionContext instead of current
* subxact's memory context. This is because AtSubCommit_Memory won't
* delete the subxact's memory context unless it is empty, and this
* can cause in memory leaks. For emptiness it just checks if the memory
* has been reset, and we cannot reset the subxact context since other
* data can be in the context that are needed by upper commits.
*
* See https://github.com/citusdata/citus/issues/3999
*/
MemoryContext old_context = MemoryContextSwitchTo(TopTransactionContext);
/* save provided subId as well as propagated SET LOCAL stmts */
SubXactContext *state = palloc(sizeof(SubXactContext));
@ -608,19 +618,34 @@ PushSubXact(SubTransactionId subId)
static void
PopSubXact(SubTransactionId subId)
{
MemoryContext old_context = MemoryContextSwitchTo(CurTransactionContext);
SubXactContext *state = linitial(activeSubXactContexts);
/*
* the previous activeSetStmts is already invalid because it's in the now-
* aborted subxact (what we're popping), so no need to free before assign-
* ing with the setLocalCmds of the popped context
*/
Assert(state->subId == subId);
activeSetStmts = state->setLocalCmds;
activeSubXactContexts = list_delete_first(activeSubXactContexts);
MemoryContextSwitchTo(old_context);
/*
* Free activeSetStmts to avoid memory leaks when we create subxacts
* for each row, e.g. in exception handling of UDFs.
*/
if (activeSetStmts != NULL)
{
pfree(activeSetStmts->data);
pfree(activeSetStmts);
}
/*
* SET LOCAL commands are local to subxact blocks. When a subxact commits
* or rolls back, we should roll back our set of SET LOCAL commands to the
* ones we had in the upper commit.
*/
activeSetStmts = state->setLocalCmds;
/*
* Free state to avoid memory leaks when we create subxacts for each row,
* e.g. in exception handling of UDFs.
*/
pfree(state);
activeSubXactContexts = list_delete_first(activeSubXactContexts);
}

View File

@ -409,6 +409,13 @@ OpenConnectionsToWorkersInParallel(TargetWorkerSet targetWorkerSet, const char *
MultiConnection *connection = StartNodeUserDatabaseConnection(connectionFlags,
nodeName, nodePort,
user, NULL);
/*
* connection can only be NULL for optional connections, which we don't
* support in this codepath.
*/
Assert((connectionFlags & OPTIONAL_CONNECTION) == 0);
Assert(connection != NULL);
connectionList = lappend(connectionList, connection);
}
return connectionList;
@ -476,6 +483,12 @@ SendCommandToWorkersParamsInternal(TargetWorkerSet targetWorkerSet, const char *
nodeName, nodePort,
user, NULL);
/*
* connection can only be NULL for optional connections, which we don't
* support in this codepath.
*/
Assert((connectionFlags & OPTIONAL_CONNECTION) == 0);
Assert(connection != NULL);
MarkRemoteTransactionCritical(connection);
connectionList = lappend(connectionList, connection);

View File

@ -14,6 +14,7 @@
#include "distributed/citus_nodefuncs.h"
#include "distributed/multi_server_executor.h"
#include "distributed/listutils.h"
#include "utils/datum.h"
@ -73,6 +74,18 @@ CitusSetTag(Node *node, int tag)
} \
while (0)
#define COPY_STRING_LIST(fldname) \
do { \
char *curString = NULL; \
List *newList = NIL; \
foreach_ptr(curString, from->fldname) { \
char *newString = curString ? pstrdup(curString) : (char *) NULL; \
newList = lappend(newList, newString); \
} \
newnode->fldname = newList; \
} \
while (0)
static void CopyTaskQuery(Task *newnode, Task *from);
static void
@ -271,13 +284,13 @@ CopyTaskQuery(Task *newnode, Task *from)
case TASK_QUERY_TEXT_PER_PLACEMENT:
{
COPY_NODE_FIELD(taskQuery.data.perPlacementQueryStrings);
COPY_STRING_LIST(taskQuery.data.perPlacementQueryStrings);
break;
}
case TASK_QUERY_TEXT_LIST:
{
COPY_NODE_FIELD(taskQuery.data.queryStringList);
COPY_STRING_LIST(taskQuery.data.queryStringList);
break;
}

View File

@ -112,6 +112,7 @@ static void MaintenanceDaemonShmemExit(int code, Datum arg);
static void MaintenanceDaemonErrorContext(void *arg);
static bool LockCitusExtension(void);
static bool MetadataSyncTriggeredCheckAndReset(MaintenanceDaemonDBData *dbData);
static void WarnMaintenanceDaemonNotStarted(void);
/*
@ -153,8 +154,10 @@ InitializeMaintenanceDaemonBackend(void)
if (dbData == NULL)
{
/* FIXME: better message, reference relevant guc in hint */
ereport(ERROR, (errmsg("ran out of database slots")));
WarnMaintenanceDaemonNotStarted();
LWLockRelease(&MaintenanceDaemonControl->lock);
return;
}
/* maintenance daemon can ignore itself */
@ -169,8 +172,6 @@ InitializeMaintenanceDaemonBackend(void)
BackgroundWorker worker;
BackgroundWorkerHandle *handle = NULL;
dbData->userOid = extensionOwner;
memset(&worker, 0, sizeof(worker));
SafeSnprintf(worker.bgw_name, sizeof(worker.bgw_name),
@ -200,11 +201,15 @@ InitializeMaintenanceDaemonBackend(void)
if (!RegisterDynamicBackgroundWorker(&worker, &handle))
{
ereport(ERROR, (errmsg("could not start maintenance background worker"),
errhint("Increasing max_worker_processes might help.")));
WarnMaintenanceDaemonNotStarted();
dbData->daemonStarted = false;
LWLockRelease(&MaintenanceDaemonControl->lock);
return;
}
dbData->daemonStarted = true;
dbData->userOid = extensionOwner;
dbData->workerPid = 0;
dbData->triggerMetadataSync = false;
LWLockRelease(&MaintenanceDaemonControl->lock);
@ -235,6 +240,17 @@ InitializeMaintenanceDaemonBackend(void)
}
/*
* WarnMaintenanceDaemonNotStarted warns that maintenanced couldn't be started.
*/
static void
WarnMaintenanceDaemonNotStarted(void)
{
ereport(WARNING, (errmsg("could not start maintenance background worker"),
errhint("Increasing max_worker_processes might help.")));
}
/*
* CitusMaintenanceDaemonMain is the maintenance daemon's main routine, it'll
* be started by the background worker infrastructure. If it errors out,

View File

@ -27,6 +27,9 @@
#include "utils/memutils.h"
static int CalculateUniformHashRangeIndex(int hashedValue, int shardCount);
/*
* LowestShardIntervalById returns the shard interval with the lowest shard
* ID from a list of shard intervals.
@ -348,20 +351,8 @@ FindShardIntervalIndex(Datum searchedValue, CitusTableCacheEntry *cacheEntry)
else
{
int hashedValue = DatumGetInt32(searchedValue);
uint64 hashTokenIncrement = HASH_TOKEN_COUNT / shardCount;
shardIndex = (uint32) (hashedValue - INT32_MIN) / hashTokenIncrement;
Assert(shardIndex <= shardCount);
/*
* If the shard count is not power of 2, the range of the last
* shard becomes larger than others. For that extra piece of range,
* we still need to use the last shard.
*/
if (shardIndex == shardCount)
{
shardIndex = shardCount - 1;
}
shardIndex = CalculateUniformHashRangeIndex(hashedValue, shardCount);
}
}
else if (partitionMethod == DISTRIBUTE_BY_NONE)
@ -442,6 +433,48 @@ SearchCachedShardInterval(Datum partitionColumnValue, ShardInterval **shardInter
}
/*
* CalculateUniformHashRangeIndex returns the index of the hash range in
* which hashedValue falls, assuming shardCount uniform hash ranges.
*
* We use 64-bit integers to avoid overflow issues during arithmetic.
*
* NOTE: This function is ONLY for hash-distributed tables with uniform
* hash ranges.
*/
static int
CalculateUniformHashRangeIndex(int hashedValue, int shardCount)
{
int64 hashedValue64 = (int64) hashedValue;
/* normalize to the 0-UINT32_MAX range */
int64 normalizedHashValue = hashedValue64 - INT32_MIN;
/* size of each hash range */
int64 hashRangeSize = HASH_TOKEN_COUNT / shardCount;
/* index of hash range into which the hash value falls */
int shardIndex = (int) (normalizedHashValue / hashRangeSize);
if (shardIndex < 0 || shardIndex > shardCount)
{
ereport(ERROR, (errmsg("bug: shard index %d out of bounds", shardIndex)));
}
/*
* If the shard count is not power of 2, the range of the last
* shard becomes larger than others. For that extra piece of range,
* we still need to use the last shard.
*/
if (shardIndex == shardCount)
{
shardIndex = shardCount - 1;
}
return shardIndex;
}
/*
* SingleReplicatedTable checks whether all shards of a distributed table, do not have
* more than one replica. If even one shard has more than one replica, this function

View File

@ -70,7 +70,7 @@ typedef enum CitusNodeTag
} CitusNodeTag;
const char** CitusNodeTagNames;
extern const char** CitusNodeTagNames;
typedef struct CitusNode

View File

@ -99,7 +99,8 @@ extern void QualifyAlterFunctionDependsStmt(Node *stmt);
extern char * DeparseAlterRoleStmt(Node *stmt);
extern char * DeparseAlterRoleSetStmt(Node *stmt);
extern Node * MakeSetStatementArgument(char *configurationName, char *configurationValue);
extern List * MakeSetStatementArguments(char *configurationName,
char *configurationValue);
extern void QualifyAlterRoleSetStmt(Node *stmt);
/* forward declarations for deparse_extension_stmts.c */

View File

@ -196,6 +196,7 @@ extern void multi_join_restriction_hook(PlannerInfo *root,
RelOptInfo *innerrel,
JoinType jointype,
JoinPathExtraData *extra);
extern bool HasUnresolvedExternParamsWalker(Node *expression, ParamListInfo boundParams);
extern bool IsModifyCommand(Query *query);
extern bool IsModifyDistributedPlan(struct DistributedPlan *distributedPlan);
extern void EnsurePartitionTableNotReplicated(Oid relationId);

View File

@ -194,6 +194,7 @@ extern Oid DistPlacementGroupidIndexId(void);
extern Oid DistObjectPrimaryKeyIndexId(void);
/* type oids */
extern Oid LookupTypeOid(char *schemaNameSting, char *typeNameString);
extern Oid CitusCopyFormatTypeId(void);
/* function oids */
@ -220,5 +221,4 @@ extern char * CitusExtensionOwnerName(void);
extern char * CurrentUserName(void);
extern const char * CurrentDatabaseName(void);
#endif /* METADATA_CACHE_H */

View File

@ -80,9 +80,21 @@ typedef enum
AGGREGATE_TOPN_UNION_AGG = 19,
AGGREGATE_ANY_VALUE = 20,
/* support for github.com/tvondra/tdigest */
AGGREGATE_TDIGEST_COMBINE = 21,
AGGREGATE_TDIGEST_ADD_DOUBLE = 22,
AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLE = 23,
AGGREGATE_TDIGEST_PERCENTILE_ADD_DOUBLEARRAY = 24,
AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLE = 25,
AGGREGATE_TDIGEST_PERCENTILE_TDIGEST_DOUBLEARRAY = 26,
AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLE = 27,
AGGREGATE_TDIGEST_PERCENTILE_OF_ADD_DOUBLEARRAY = 28,
AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLE = 29,
AGGREGATE_TDIGEST_PERCENTILE_OF_TDIGEST_DOUBLEARRAY = 30,
/* AGGREGATE_CUSTOM must come last */
AGGREGATE_CUSTOM_COMBINE = 21,
AGGREGATE_CUSTOM_ROW_GATHER = 22,
AGGREGATE_CUSTOM_COMBINE = 31,
AGGREGATE_CUSTOM_ROW_GATHER = 32,
} AggregateType;

View File

@ -497,7 +497,10 @@ extern Task * CreateBasicTask(uint64 jobId, uint32 taskId, TaskType taskType,
char *queryString);
extern OpExpr * MakeOpExpression(Var *variable, int16 strategyNumber);
extern Node * AddAnyValueAggregates(Node *node, void *context);
extern Node * WrapUngroupedVarsInAnyValueAggregate(Node *expression,
List *groupClauseList,
List *targetList,
bool checkExpressionEquality);
/*
* Function declarations for building, updating constraints and simple operator

View File

@ -20,5 +20,7 @@
extern List * PruneShards(Oid relationId, Index rangeTableId, List *whereClauseList,
Const **partitionValueConst);
extern bool ContainsFalseClause(List *whereClauseList);
extern Const * TransformPartitionRestrictionValue(Var *partitionColumn,
Const *restrictionValue,
bool missingOk);
#endif /* SHARD_PRUNING_H_ */

View File

@ -0,0 +1,27 @@
/*-------------------------------------------------------------------------
*
* tdigest_extension.c
* Helper functions to get access to tdigest specific data.
*
* Copyright (c) Citus Data, Inc.
*-------------------------------------------------------------------------
*/
#ifndef CITUS_TDIGEST_EXTENSION_H
#define CITUS_TDIGEST_EXTENSION_H
/* tdigest related functions */
extern Oid TDigestExtensionSchema(void);
extern Oid TDigestExtensionTypeOid(void);
extern Oid TDigestExtensionAggTDigest1(void);
extern Oid TDigestExtensionAggTDigest2(void);
extern Oid TDigestExtensionAggTDigestPercentile2(void);
extern Oid TDigestExtensionAggTDigestPercentile2a(void);
extern Oid TDigestExtensionAggTDigestPercentile3(void);
extern Oid TDigestExtensionAggTDigestPercentile3a(void);
extern Oid TDigestExtensionAggTDigestPercentileOf2(void);
extern Oid TDigestExtensionAggTDigestPercentileOf2a(void);
extern Oid TDigestExtensionAggTDigestPercentileOf3(void);
extern Oid TDigestExtensionAggTDigestPercentileOf3a(void);
#endif /* CITUS_TDIGEST_EXTENSION_H */

View File

@ -1,4 +1,5 @@
CREATE SCHEMA alter_role;
CREATE SCHEMA ",CitUs,.TeeN!?";
-- test if the passowrd of the extension owner can be upgraded
ALTER ROLE CURRENT_USER PASSWORD 'password123' VALID UNTIL 'infinity';
SELECT run_command_on_workers($$SELECT row(rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, rolpassword, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = current_user$$);
@ -111,6 +112,12 @@ SELECT run_command_on_workers('SHOW enable_hashagg');
(localhost,57638,t,off)
(1 row)
-- provide a list of values in a supported configuration
ALTER ROLE CURRENT_USER SET search_path TO ",CitUs,.TeeN!?", alter_role, public;
-- test user defined GUCs that appear to be a list, but instead a single string
ALTER ROLE ALL SET public.myguc TO "Hello, World";
-- test for configuration values that should not be downcased even when unquoted
ALTER ROLE CURRENT_USER SET lc_messages TO 'C';
-- add worker and check all settings are copied
SELECT 1 FROM master_add_node('localhost', :worker_1_port);
?column?
@ -139,6 +146,27 @@ SELECT run_command_on_workers('SHOW enable_hashagg');
(localhost,57638,t,off)
(2 rows)
SELECT run_command_on_workers('SHOW search_path');
run_command_on_workers
---------------------------------------------------------------------
(localhost,57637,t,""",CitUs,.TeeN!?"", alter_role, public")
(localhost,57638,t,""",CitUs,.TeeN!?"", alter_role, public")
(2 rows)
SELECT run_command_on_workers('SHOW lc_messages');
run_command_on_workers
---------------------------------------------------------------------
(localhost,57637,t,C)
(localhost,57638,t,C)
(2 rows)
SELECT run_command_on_workers('SHOW public.myguc');
run_command_on_workers
---------------------------------------------------------------------
(localhost,57637,t,"Hello, World")
(localhost,57638,t,"Hello, World")
(2 rows)
-- reset to default values
ALTER ROLE CURRENT_USER RESET enable_hashagg;
SELECT run_command_on_workers('SHOW enable_hashagg');
@ -226,4 +254,4 @@ SELECT run_command_on_workers('SHOW enable_hashjoin');
(localhost,57638,t,on)
(2 rows)
DROP SCHEMA alter_role CASCADE;
DROP SCHEMA alter_role, ",CitUs,.TeeN!?" CASCADE;

View File

@ -0,0 +1,133 @@
SET citus.next_shard_id TO 20080000;
CREATE SCHEMA anonymous_columns;
SET search_path TO anonymous_columns;
CREATE TABLE t0 (a int PRIMARY KEY, b int, "?column?" text);
SELECT create_distributed_table('t0', 'a');
create_distributed_table
---------------------------------------------------------------------
(1 row)
INSERT INTO t0 VALUES (1, 2, 'hello'), (2, 4, 'world');
SELECT "?column?" FROM t0 ORDER BY 1;
?column?
---------------------------------------------------------------------
hello
world
(2 rows)
WITH a AS (SELECT * FROM t0) SELECT "?column?" FROM a ORDER BY 1;
?column?
---------------------------------------------------------------------
hello
world
(2 rows)
WITH a AS (SELECT '' FROM t0) SELECT * FROM a;
?column?
---------------------------------------------------------------------
(2 rows)
-- test CTE's that could be rewritten as subquery
WITH a AS (SELECT '' FROM t0 GROUP BY a) SELECT * FROM a;
?column?
---------------------------------------------------------------------
(2 rows)
WITH a AS (SELECT '' FROM t0 GROUP BY b) SELECT * FROM a;
?column?
---------------------------------------------------------------------
(2 rows)
WITH a AS (SELECT '','' FROM t0 GROUP BY a) SELECT * FROM a;
?column? | ?column?
---------------------------------------------------------------------
|
|
(2 rows)
WITH a AS (SELECT '','' FROM t0 GROUP BY b) SELECT * FROM a;
?column? | ?column?
---------------------------------------------------------------------
|
|
(2 rows)
WITH a AS (SELECT 1, * FROM t0 WHERE a = 1) SELECT * FROM a;
?column? | a | b | ?column?
---------------------------------------------------------------------
1 | 1 | 2 | hello
(1 row)
-- test CTE's that are referenced multiple times and hence need to stay CTE's
WITH a AS (SELECT '' FROM t0 WHERE a = 1) SELECT * FROM a, a b;
?column? | ?column?
---------------------------------------------------------------------
|
(1 row)
WITH a AS (SELECT '','' FROM t0 WHERE a = 42) SELECT * FROM a, a b;
?column? | ?column? | ?column? | ?column?
---------------------------------------------------------------------
(0 rows)
-- test with explicit subqueries
SELECT * FROM (SELECT a, '' FROM t0 GROUP BY a) as foo ORDER BY 1;
a | ?column?
---------------------------------------------------------------------
1 |
2 |
(2 rows)
SELECT * FROM (SELECT a, '', '' FROM t0 GROUP BY a ) as foo ORDER BY 1;
a | ?column? | ?column?
---------------------------------------------------------------------
1 | |
2 | |
(2 rows)
SELECT * FROM (SELECT b, '' FROM t0 GROUP BY b ) as foo ORDER BY 1;
b | ?column?
---------------------------------------------------------------------
2 |
4 |
(2 rows)
SELECT * FROM (SELECT b, '', '' FROM t0 GROUP BY b ) as foo ORDER BY 1;
b | ?column? | ?column?
---------------------------------------------------------------------
2 | |
4 | |
(2 rows)
-- some tests that follow very similar codeoaths
SELECT a + 1 FROM t0 ORDER BY 1;
?column?
---------------------------------------------------------------------
2
3
(2 rows)
SELECT a + 1, a - 1 FROM t0 ORDER BY 1;
?column? | ?column?
---------------------------------------------------------------------
2 | 0
3 | 1
(2 rows)
WITH cte1 AS (SELECT row_to_json(row(a))->'f1' FROM t0) SELECT * FROM cte1 ORDER BY 1::text;
?column?
---------------------------------------------------------------------
1
2
(2 rows)
-- clean up after test
SET client_min_messages TO WARNING;
DROP SCHEMA anonymous_columns CASCADE;

View File

@ -316,7 +316,7 @@ insert into stock VALUES
SELECT create_distributed_table('stock','s_w_id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$ch_bench_having.stock$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -324,7 +324,7 @@ insert into stock VALUES
SELECT create_distributed_table('stock','s_w_id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$ch_bench_having.stock$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -146,7 +146,7 @@ NOTICE: executing the copy locally for shard xxxxx
NOTICE: Copying data from local table...
NOTICE: executing the copy locally for shard xxxxx
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$coordinator_shouldhaveshards.dist_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -182,7 +182,7 @@ NOTICE: executing the copy locally for shard xxxxx
NOTICE: Copying data from local table...
NOTICE: executing the copy locally for shard xxxxx
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$coordinator_shouldhaveshards.dist_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -375,13 +375,48 @@ NOTICE: executing the command locally: SELECT a.count, b.x, b.y, c.a, c.b, d.co
100 | 3 | 2 | 3 | 2 | 1
(1 row)
-- issue #3801
SET citus.shard_replication_factor TO 2;
CREATE TABLE dist_table(a int);
ERROR: relation "dist_table" already exists
SELECT create_distributed_table('dist_table', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$coordinator_shouldhaveshards.dist_table$$)
create_distributed_table
---------------------------------------------------------------------
(1 row)
BEGIN;
-- this will use perPlacementQueryStrings, make sure it works correctly with
-- copying task
INSERT INTO dist_table SELECT a + 1 FROM dist_table;
ROLLBACK;
BEGIN;
SET citus.shard_replication_factor TO 2;
CREATE TABLE dist_table1(a int);
-- this will use queryStringList, make sure it works correctly with
-- copying task
SELECT create_distributed_table('dist_table1', 'a');
NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503023, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503023, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres')
NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503025, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503025, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres')
NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503026, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503026, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres')
NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503028, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer)');SELECT worker_apply_shard_ddl_command (1503028, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres')
create_distributed_table
---------------------------------------------------------------------
(1 row)
ROLLBACK;
RESET citus.enable_cte_inlining;
DELETE FROM test;
DROP TABLE test;
DROP TABLE dist_table;
DROP SCHEMA coordinator_shouldhaveshards CASCADE;
NOTICE: drop cascades to 4 other objects
DETAIL: drop cascades to table dist_table
drop cascades to table ref
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table ref
drop cascades to table ref_1503016
drop cascades to table local
SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', false);

View File

@ -165,7 +165,7 @@ DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: Creating router plan
DEBUG: Plan is router executable
DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value, (SELECT 1) FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1) foo
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) top_cte, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) bar
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) top_cte, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) bar(key, value, other_value, "?column?")
DEBUG: Creating router plan
DEBUG: Plan is router executable
count
@ -249,7 +249,7 @@ DEBUG: CTE cte_2 is going to be inlined via distributed planning
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT cte_1.key, cte_1.value, cte_1.other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON (true))
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT cte_1.key, cte_1.value, cte_1.other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo(key, value, other_value, "?column?") JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON (true))
DEBUG: Router planner cannot handle multi-shard select queries
count
---------------------------------------------------------------------

View File

@ -153,7 +153,7 @@ DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: Creating router plan
DEBUG: Plan is router executable
DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value, (SELECT 1) FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1) foo
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) top_cte, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) bar
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) top_cte, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) bar(key, value, other_value, "?column?")
DEBUG: Creating router plan
DEBUG: Plan is router executable
count
@ -237,7 +237,7 @@ DEBUG: CTE cte_2 is going to be inlined via distributed planning
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT cte_1.key, cte_1.value, cte_1.other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON (true))
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT cte_1.key, cte_1.value, cte_1.other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo(key, value, other_value, "?column?") JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON (true))
DEBUG: Router planner cannot handle multi-shard select queries
count
---------------------------------------------------------------------

View File

@ -5,7 +5,7 @@ INSERT INTO tt1 VALUES(1,2),(2,3),(3,4);
SELECT create_distributed_table('tt1','id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$cte_nested_modifications.tt1$$)
create_distributed_table
---------------------------------------------------------------------
@ -17,7 +17,7 @@ INSERT INTO tt2 VALUES(3,3),(4,4),(5,5);
SELECT create_distributed_table('tt2','id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$cte_nested_modifications.tt2$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -5,7 +5,7 @@ INSERT INTO tt1 VALUES(1,2),(2,3),(3,4);
SELECT create_distributed_table('tt1','id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$cte_prepared_modify.tt1$$)
create_distributed_table
---------------------------------------------------------------------
@ -17,7 +17,7 @@ INSERT INTO tt2 VALUES(3,3),(4,4),(5,5);
SELECT create_distributed_table('tt2','id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$cte_prepared_modify.tt2$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -36,7 +36,7 @@ INSERT INTO test_propagate VALUES (1, 'aesop', U&'\00E4sop'), (2, U&'Vo\1E9Er',
SELECT create_distributed_table('test_propagate', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$collation_tests.test_propagate$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -299,7 +299,7 @@ INSERT INTO
VALUES ('3', (WITH vals AS (SELECT 3) select * from vals));
DEBUG: CTE vals is going to be inlined via distributed planning
DEBUG: generating subplan XXX_1 for CTE vals: SELECT 3
DEBUG: Plan XXX query after replacing subqueries and CTEs: INSERT INTO recursive_dml_queries.second_distributed_table (tenant_id, dept) VALUES ('3'::text, (SELECT vals."?column?" FROM (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer)) vals))
DEBUG: Plan XXX query after replacing subqueries and CTEs: INSERT INTO recursive_dml_queries.second_distributed_table (tenant_id, dept) VALUES ('3'::text, (SELECT vals."?column?" FROM (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer)) vals("?column?")))
ERROR: subqueries are not supported within INSERT queries
HINT: Try rewriting your queries with 'INSERT INTO ... SELECT' syntax.
INSERT INTO

View File

@ -14,7 +14,7 @@ INSERT INTO test VALUES
SELECT create_reference_table('ref');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$expression_reference_join.ref$$)
create_reference_table
---------------------------------------------------------------------
@ -24,7 +24,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('test', 'x');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$expression_reference_join.test$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -62,7 +62,7 @@ INSERT INTO r1 (id, name) VALUES
SELECT create_reference_table('r1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$fail_connect.r1$$)
create_reference_table
---------------------------------------------------------------------

View File

@ -225,7 +225,7 @@ SELECT citus.mitmproxy('conn.onCommandComplete(command="COPY").kill()');
SELECT create_distributed_table('test_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$create_distributed_table_non_empty_failure.test_table$$)
ERROR: failed to COPY to shard xxxxx on localhost:xxxxx
SELECT count(*) FROM pg_dist_shard WHERE logicalrelid='create_distributed_table_non_empty_failure.test_table'::regclass;
@ -260,7 +260,7 @@ SELECT citus.mitmproxy('conn.onCommandComplete(command="COPY").cancel(' || pg_b
SELECT create_distributed_table('test_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$create_distributed_table_non_empty_failure.test_table$$)
ERROR: canceling statement due to user request
SELECT count(*) FROM pg_dist_shard WHERE logicalrelid='create_distributed_table_non_empty_failure.test_table'::regclass;

View File

@ -108,7 +108,7 @@ SELECT citus.mitmproxy('conn.onCommandComplete(command="COPY 3").kill()');
SELECT create_reference_table('ref_table');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$failure_reference_table.ref_table$$)
ERROR: failed to COPY to shard xxxxx on localhost:xxxxx
SELECT count(*) FROM pg_dist_shard_placement;
@ -127,7 +127,7 @@ SELECT citus.mitmproxy('conn.onCommandComplete(command="COPY 3").cancel(' || pg_
SELECT create_reference_table('ref_table');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$failure_reference_table.ref_table$$)
ERROR: canceling statement due to user request
SELECT count(*) FROM pg_dist_shard_placement;
@ -219,7 +219,7 @@ BEGIN;
SELECT create_reference_table('ref_table');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$failure_reference_table.ref_table$$)
create_reference_table
---------------------------------------------------------------------
@ -246,7 +246,7 @@ BEGIN;
SELECT create_reference_table('ref_table');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$failure_reference_table.ref_table$$)
create_reference_table
---------------------------------------------------------------------

View File

@ -427,7 +427,7 @@ CREATE TABLE t3 AS SELECT * FROM t2;
SELECT create_distributed_table('t3', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_shard.t3$$)
create_distributed_table
---------------------------------------------------------------------
@ -527,7 +527,7 @@ CREATE TABLE t3 AS SELECT * FROM t2;
SELECT create_distributed_table('t3', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_shard.t3$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -1273,7 +1273,7 @@ BEGIN;
SELECT create_reference_table('test_table_1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_fkey_to_ref_in_tx.test_table_1$$)
create_reference_table
---------------------------------------------------------------------
@ -1300,7 +1300,7 @@ BEGIN;
SELECT create_reference_table('test_table_1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_fkey_to_ref_in_tx.test_table_1$$)
create_reference_table
---------------------------------------------------------------------

View File

@ -747,7 +747,7 @@ INSERT INTO referencing_table VALUES (1,1), (2,2), (3,3);
SELECT create_reference_table('referenced_table');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$fkey_reference_table.referenced_table$$)
create_reference_table
---------------------------------------------------------------------
@ -1309,7 +1309,7 @@ BEGIN;
SELECT create_reference_table('test_table_1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$fkey_reference_table.test_table_1$$)
create_reference_table
---------------------------------------------------------------------

View File

@ -491,7 +491,7 @@ NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1
NOTICE: executing the copy locally for shard xxxxx
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$local_shard_copy.ref_table$$)
create_reference_table
---------------------------------------------------------------------

View File

@ -1674,7 +1674,7 @@ RESET client_min_messages;
RESET citus.log_local_commands;
\c - - - :master_port
SET citus.next_shard_id TO 1480000;
-- local execution with custom type
-- test both local and remote execution with custom type
SET citus.replication_model TO "streaming";
SET citus.shard_replication_factor TO 1;
CREATE TYPE invite_resp AS ENUM ('yes', 'no', 'maybe');
@ -1690,6 +1690,273 @@ SELECT create_distributed_table('event_responses', 'event_id');
(1 row)
INSERT INTO event_responses VALUES (1, 1, 'yes'), (2, 2, 'yes'), (3, 3, 'no'), (4, 4, 'no');
CREATE OR REPLACE FUNCTION regular_func(p invite_resp)
RETURNS int AS $$
DECLARE
q1Result INT;
q2Result INT;
q3Result INT;
BEGIN
SELECT count(*) INTO q1Result FROM event_responses WHERE response = $1;
SELECT count(*) INTO q2Result FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1;
SELECT count(*) INTO q3Result FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo;
RETURN q3Result+q2Result+q1Result;
END;
$$ LANGUAGE plpgsql;
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
SELECT regular_func('yes');
regular_func
---------------------------------------------------------------------
6
(1 row)
CREATE OR REPLACE PROCEDURE regular_procedure(p invite_resp)
AS $$
BEGIN
PERFORM * FROM event_responses WHERE response = $1;
PERFORM * FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1;
PERFORM * FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo;
END;
$$ LANGUAGE plpgsql;
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
PREPARE multi_shard_no_dist_key(invite_resp) AS select * from event_responses where response = $1::invite_resp LIMIT 1;
EXECUTE multi_shard_no_dist_key('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE multi_shard_no_dist_key('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE multi_shard_no_dist_key('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE multi_shard_no_dist_key('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE multi_shard_no_dist_key('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE multi_shard_no_dist_key('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE multi_shard_no_dist_key('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
PREPARE multi_shard_with_dist_key(int, invite_resp) AS select * from event_responses where event_id > $1 AND response = $2::invite_resp LIMIT 1;
EXECUTE multi_shard_with_dist_key(1, 'yes');
event_id | user_id | response
---------------------------------------------------------------------
2 | 2 | yes
(1 row)
EXECUTE multi_shard_with_dist_key(1, 'yes');
event_id | user_id | response
---------------------------------------------------------------------
2 | 2 | yes
(1 row)
EXECUTE multi_shard_with_dist_key(1, 'yes');
event_id | user_id | response
---------------------------------------------------------------------
2 | 2 | yes
(1 row)
EXECUTE multi_shard_with_dist_key(1, 'yes');
event_id | user_id | response
---------------------------------------------------------------------
2 | 2 | yes
(1 row)
EXECUTE multi_shard_with_dist_key(1, 'yes');
event_id | user_id | response
---------------------------------------------------------------------
2 | 2 | yes
(1 row)
EXECUTE multi_shard_with_dist_key(1, 'yes');
event_id | user_id | response
---------------------------------------------------------------------
2 | 2 | yes
(1 row)
EXECUTE multi_shard_with_dist_key(1, 'yes');
event_id | user_id | response
---------------------------------------------------------------------
2 | 2 | yes
(1 row)
PREPARE query_pushdown_no_dist_key(invite_resp) AS select * from event_responses e1 LEFT JOIN event_responses e2 USING(event_id) where e1.response = $1::invite_resp LIMIT 1;
EXECUTE query_pushdown_no_dist_key('yes');
event_id | user_id | response | user_id | response
---------------------------------------------------------------------
1 | 1 | yes | 1 | yes
(1 row)
EXECUTE query_pushdown_no_dist_key('yes');
event_id | user_id | response | user_id | response
---------------------------------------------------------------------
1 | 1 | yes | 1 | yes
(1 row)
EXECUTE query_pushdown_no_dist_key('yes');
event_id | user_id | response | user_id | response
---------------------------------------------------------------------
1 | 1 | yes | 1 | yes
(1 row)
EXECUTE query_pushdown_no_dist_key('yes');
event_id | user_id | response | user_id | response
---------------------------------------------------------------------
1 | 1 | yes | 1 | yes
(1 row)
EXECUTE query_pushdown_no_dist_key('yes');
event_id | user_id | response | user_id | response
---------------------------------------------------------------------
1 | 1 | yes | 1 | yes
(1 row)
EXECUTE query_pushdown_no_dist_key('yes');
event_id | user_id | response | user_id | response
---------------------------------------------------------------------
1 | 1 | yes | 1 | yes
(1 row)
EXECUTE query_pushdown_no_dist_key('yes');
event_id | user_id | response | user_id | response
---------------------------------------------------------------------
1 | 1 | yes | 1 | yes
(1 row)
PREPARE insert_select_via_coord(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp LIMIT 1 ON CONFLICT (event_id, user_id) DO NOTHING ;
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
PREPARE insert_select_pushdown(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp ON CONFLICT (event_id, user_id) DO NOTHING;
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
PREPARE router_select_with_no_dist_key_filter(invite_resp) AS select * from event_responses where event_id = 1 AND response = $1::invite_resp LIMIT 1;
EXECUTE router_select_with_no_dist_key_filter('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE router_select_with_no_dist_key_filter('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE router_select_with_no_dist_key_filter('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE router_select_with_no_dist_key_filter('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE router_select_with_no_dist_key_filter('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE router_select_with_no_dist_key_filter('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
EXECUTE router_select_with_no_dist_key_filter('yes');
event_id | user_id | response
---------------------------------------------------------------------
1 | 1 | yes
(1 row)
-- rest of the tests assume the table is empty
TRUNCATE event_responses;
CREATE OR REPLACE PROCEDURE register_for_event(p_event_id int, p_user_id int, p_choice invite_resp)
LANGUAGE plpgsql AS $fn$
BEGIN

View File

@ -139,7 +139,7 @@ WHERE lineitem_local_to_hash_part.l_orderkey=orders_local_to_hash_part.o_orderke
SELECT create_distributed_table('lineitem_local_to_hash_part', 'l_orderkey');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$materialized_view.lineitem_local_to_hash_part$$)
create_distributed_table
---------------------------------------------------------------------
@ -149,7 +149,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('orders_local_to_hash_part', 'o_orderkey');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$materialized_view.orders_local_to_hash_part$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -561,7 +561,7 @@ SET search_path TO 'sc3';
SELECT create_distributed_table('alter_add_prim_key', 'x');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc3.alter_add_prim_key$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -202,7 +202,7 @@ HINT: Empty your table before distributing it.
SELECT create_distributed_table('data_load_test', 'col1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test$$)
create_distributed_table
---------------------------------------------------------------------
@ -264,7 +264,7 @@ INSERT INTO data_load_test VALUES (132, 'hello');
SELECT create_distributed_table('data_load_test', 'col1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test$$)
create_distributed_table
---------------------------------------------------------------------
@ -288,7 +288,7 @@ INSERT INTO data_load_test1 VALUES (132, 'hello');
SELECT create_distributed_table('data_load_test1', 'col1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test1$$)
create_distributed_table
---------------------------------------------------------------------
@ -300,7 +300,7 @@ INSERT INTO data_load_test2 VALUES (132, 'world');
SELECT create_distributed_table('data_load_test2', 'col1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test2$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -238,7 +238,7 @@ INSERT INTO data_load_test VALUES (132, 'hello');
SELECT create_distributed_table('data_load_test', 'col1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test$$)
create_distributed_table
---------------------------------------------------------------------
@ -255,7 +255,7 @@ INSERT INTO data_load_test VALUES (132, 'hello');
SELECT create_distributed_table('data_load_test', 'col1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test$$)
create_distributed_table
---------------------------------------------------------------------
@ -271,7 +271,7 @@ INSERT INTO data_load_test VALUES (132, 'hello');
SELECT create_distributed_table('data_load_test', 'col1');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test$$)
create_distributed_table
---------------------------------------------------------------------
@ -289,7 +289,7 @@ ALTER TABLE data_load_test DROP COLUMN col1;
SELECT create_distributed_table('data_load_test', 'col3');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.data_load_test$$)
create_distributed_table
---------------------------------------------------------------------
@ -384,7 +384,7 @@ INSERT INTO rollback_table VALUES(3, 'Name_3');
SELECT create_distributed_table('rollback_table','id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.rollback_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -514,7 +514,7 @@ INSERT INTO tt1 VALUES(1);
SELECT create_distributed_table('tt1','id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.tt1$$)
create_distributed_table
---------------------------------------------------------------------
@ -573,7 +573,7 @@ CREATE TABLE stage_table (LIKE sample_table);
SELECT create_distributed_table('stage_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.stage_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -647,7 +647,7 @@ insert into sc.ref SELECT s FROM generate_series(0, 100) s;
SELECT create_reference_table('sc.ref');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc.ref$$)
create_reference_table
---------------------------------------------------------------------
@ -659,7 +659,7 @@ insert into sc.hash SELECT s FROM generate_series(0, 100) s;
SELECT create_distributed_table('sc.hash', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc.hash$$)
create_distributed_table
---------------------------------------------------------------------
@ -675,7 +675,7 @@ insert into sc2.hash SELECT s FROM generate_series(0, 100) s;
SELECT create_distributed_table('sc2.hash', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc2.hash$$)
create_distributed_table
---------------------------------------------------------------------
@ -687,7 +687,7 @@ insert into sc2.ref SELECT s FROM generate_series(0, 100) s;
SELECT create_reference_table('sc2.ref');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc2.ref$$)
create_reference_table
---------------------------------------------------------------------
@ -731,7 +731,7 @@ ALTER TABLE alter_replica_table REPLICA IDENTITY USING INDEX alter_replica_table
SELECT create_distributed_table('alter_replica_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc4.alter_replica_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -759,7 +759,7 @@ ALTER TABLE sc5.alter_replica_table REPLICA IDENTITY FULL;
SELECT create_distributed_table('sc5.alter_replica_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc5.alter_replica_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -787,7 +787,7 @@ ALTER TABLE sc6.alter_replica_table REPLICA IDENTITY USING INDEX unique_idx;
SELECT create_distributed_table('sc6.alter_replica_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sc6.alter_replica_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -814,7 +814,7 @@ ALTER TABLE alter_replica_table REPLICA IDENTITY USING INDEX unique_idx;
SELECT create_distributed_table('alter_replica_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.alter_replica_table$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -32,6 +32,35 @@ END;
$$;
$definition$ create_function_test_maintenance_worker
\gset
CREATE TABLE prev_objects(description text);
CREATE TABLE extension_diff(previous_object text COLLATE "C",
current_object text COLLATE "C");
CREATE FUNCTION print_extension_changes()
RETURNS TABLE(previous_object text, current_object text)
AS $func$
BEGIN
TRUNCATE TABLE extension_diff;
CREATE TABLE current_objects AS
SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS description
FROM pg_catalog.pg_depend, pg_catalog.pg_extension e
WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass
AND refobjid = e.oid
AND deptype = 'e'
AND e.extname='citus';
INSERT INTO extension_diff
SELECT p.description previous_object, c.description current_object
FROM current_objects c FULL JOIN prev_objects p
ON p.description = c.description
WHERE p.description is null OR c.description is null;
DROP TABLE prev_objects;
ALTER TABLE current_objects RENAME TO prev_objects;
RETURN QUERY SELECT * FROM extension_diff ORDER BY 1, 2;
END
$func$ LANGUAGE plpgsql;
CREATE SCHEMA test;
:create_function_test_maintenance_worker
-- check maintenance daemon is started
@ -120,21 +149,251 @@ ALTER EXTENSION citus UPDATE TO '9.0-2';
ALTER EXTENSION citus UPDATE TO '9.1-1';
ALTER EXTENSION citus UPDATE TO '9.2-1';
ALTER EXTENSION citus UPDATE TO '9.2-2';
-- Snapshot of state at 9.2-2
SELECT * FROM print_extension_changes();
previous_object | current_object
---------------------------------------------------------------------
| event trigger citus_cascade_to_partition
| function alter_role_if_exists(text,text)
| function any_value(anyelement)
| function any_value_agg(anyelement,anyelement)
| function array_cat_agg(anyarray)
| function assign_distributed_transaction_id(integer,bigint,timestamp with time zone)
| function authinfo_valid(text)
| function broadcast_intermediate_result(text,text)
| function check_distributed_deadlocks()
| function citus_add_rebalance_strategy(name,regproc,regproc,regproc,real,real)
| function citus_blocking_pids(integer)
| function citus_create_restore_point(text)
| function citus_dist_stat_activity()
| function citus_drop_trigger()
| function citus_executor_name(integer)
| function citus_extradata_container(internal)
| function citus_finish_pg_upgrade()
| function citus_internal.find_groupid_for_node(text,integer)
| function citus_internal.pg_dist_node_trigger_func()
| function citus_internal.pg_dist_rebalance_strategy_enterprise_check()
| function citus_internal.pg_dist_rebalance_strategy_trigger_func()
| function citus_internal.pg_dist_shard_placement_trigger_func()
| function citus_internal.refresh_isolation_tester_prepared_statement()
| function citus_internal.replace_isolation_tester_func()
| function citus_internal.restore_isolation_tester_func()
| function citus_isolation_test_session_is_blocked(integer,integer[])
| function citus_json_concatenate(json,json)
| function citus_json_concatenate_final(json)
| function citus_jsonb_concatenate(jsonb,jsonb)
| function citus_jsonb_concatenate_final(jsonb)
| function citus_node_capacity_1(integer)
| function citus_prepare_pg_upgrade()
| function citus_query_stats()
| function citus_relation_size(regclass)
| function citus_server_id()
| function citus_set_default_rebalance_strategy(text)
| function citus_shard_allowed_on_node_true(bigint,integer)
| function citus_shard_cost_1(bigint)
| function citus_shard_cost_by_disk_size(bigint)
| function citus_stat_statements()
| function citus_stat_statements_reset()
| function citus_table_is_visible(oid)
| function citus_table_size(regclass)
| function citus_text_send_as_jsonb(text)
| function citus_total_relation_size(regclass)
| function citus_truncate_trigger()
| function citus_validate_rebalance_strategy_functions(regproc,regproc,regproc)
| function citus_version()
| function citus_worker_stat_activity()
| function column_name_to_column(regclass,text)
| function column_to_column_name(regclass,text)
| function coord_combine_agg(oid,cstring,anyelement)
| function coord_combine_agg_ffunc(internal,oid,cstring,anyelement)
| function coord_combine_agg_sfunc(internal,oid,cstring,anyelement)
| function create_distributed_function(regprocedure,text,text)
| function create_distributed_table(regclass,text,citus.distribution_type,text)
| function create_intermediate_result(text,text)
| function create_reference_table(regclass)
| function distributed_tables_colocated(regclass,regclass)
| function dump_global_wait_edges()
| function dump_local_wait_edges()
| function fetch_intermediate_results(text[],text,integer)
| function get_all_active_transactions()
| function get_colocated_shard_array(bigint)
| function get_colocated_table_array(regclass)
| function get_current_transaction_id()
| function get_global_active_transactions()
| function get_rebalance_progress()
| function get_rebalance_table_shards_plan(regclass,real,integer,bigint[],boolean,name)
| function get_shard_id_for_distribution_column(regclass,"any")
| function isolate_tenant_to_new_shard(regclass,"any",text)
| function json_cat_agg(json)
| function jsonb_cat_agg(jsonb)
| function lock_relation_if_exists(text,text)
| function lock_shard_metadata(integer,bigint[])
| function lock_shard_resources(integer,bigint[])
| function mark_tables_colocated(regclass,regclass[])
| function master_activate_node(text,integer)
| function master_add_inactive_node(text,integer,integer,noderole,name)
| function master_add_node(text,integer,integer,noderole,name)
| function master_add_secondary_node(text,integer,text,integer,name)
| function master_append_table_to_shard(bigint,text,text,integer)
| function master_apply_delete_command(text)
| function master_conninfo_cache_invalidate()
| function master_copy_shard_placement(bigint,text,integer,text,integer,boolean,citus.shard_transfer_mode)
| function master_create_distributed_table(regclass,text,citus.distribution_type)
| function master_create_empty_shard(text)
| function master_create_worker_shards(text,integer,integer)
| function master_disable_node(text,integer)
| function master_dist_local_group_cache_invalidate()
| function master_dist_node_cache_invalidate()
| function master_dist_object_cache_invalidate()
| function master_dist_partition_cache_invalidate()
| function master_dist_placement_cache_invalidate()
| function master_dist_shard_cache_invalidate()
| function master_drain_node(text,integer,citus.shard_transfer_mode,name)
| function master_drop_all_shards(regclass,text,text)
| function master_drop_sequences(text[])
| function master_get_active_worker_nodes()
| function master_get_new_placementid()
| function master_get_new_shardid()
| function master_get_table_ddl_events(text)
| function master_get_table_metadata(text)
| function master_modify_multiple_shards(text)
| function master_move_shard_placement(bigint,text,integer,text,integer,citus.shard_transfer_mode)
| function master_remove_distributed_table_metadata_from_workers(regclass,text,text)
| function master_remove_node(text,integer)
| function master_remove_partition_metadata(regclass,text,text)
| function master_run_on_worker(text[],integer[],text[],boolean)
| function master_set_node_property(text,integer,text,boolean)
| function master_unmark_object_distributed(oid,oid,integer)
| function master_update_node(integer,text,integer,boolean,integer)
| function master_update_shard_statistics(bigint)
| function master_update_table_statistics(regclass)
| function poolinfo_valid(text)
| function read_intermediate_result(text,citus_copy_format)
| function read_intermediate_results(text[],citus_copy_format)
| function rebalance_table_shards(regclass,real,integer,bigint[],citus.shard_transfer_mode,boolean,name)
| function recover_prepared_transactions()
| function relation_is_a_known_shard(regclass)
| function replicate_table_shards(regclass,integer,integer,bigint[],citus.shard_transfer_mode)
| function role_exists(name)
| function run_command_on_colocated_placements(regclass,regclass,text,boolean)
| function run_command_on_placements(regclass,text,boolean)
| function run_command_on_shards(regclass,text,boolean)
| function run_command_on_workers(text,boolean)
| function shard_name(regclass,bigint)
| function start_metadata_sync_to_node(text,integer)
| function stop_metadata_sync_to_node(text,integer)
| function task_tracker_assign_task(bigint,integer,text)
| function task_tracker_cleanup_job(bigint)
| function task_tracker_conninfo_cache_invalidate()
| function task_tracker_task_status(bigint,integer)
| function upgrade_to_reference_table(regclass)
| function worker_append_table_to_shard(text,text,text,integer)
| function worker_apply_inter_shard_ddl_command(bigint,text,bigint,text,text)
| function worker_apply_sequence_command(text)
| function worker_apply_sequence_command(text,regtype)
| function worker_apply_shard_ddl_command(bigint,text)
| function worker_apply_shard_ddl_command(bigint,text,text)
| function worker_cleanup_job_schema_cache()
| function worker_create_or_replace_object(text)
| function worker_create_schema(bigint,text)
| function worker_create_truncate_trigger(regclass)
| function worker_drop_distributed_table(text)
| function worker_execute_sql_task(bigint,integer,text,boolean)
| function worker_fetch_foreign_file(text,text,bigint,text[],integer[])
| function worker_fetch_partition_file(bigint,integer,integer,integer,text,integer)
| function worker_hash("any")
| function worker_hash_partition_table(bigint,integer,text,text,oid,anyarray)
| function worker_merge_files_and_run_query(bigint,integer,text,text)
| function worker_merge_files_into_table(bigint,integer,text[],text[])
| function worker_partial_agg(oid,anyelement)
| function worker_partial_agg_ffunc(internal)
| function worker_partial_agg_sfunc(internal,oid,anyelement)
| function worker_partition_query_result(text,text,integer,citus.distribution_type,text[],text[],boolean)
| function worker_range_partition_table(bigint,integer,text,text,oid,anyarray)
| function worker_repartition_cleanup(bigint)
| schema citus
| schema citus_internal
| sequence pg_dist_colocationid_seq
| sequence pg_dist_groupid_seq
| sequence pg_dist_node_nodeid_seq
| sequence pg_dist_placement_placementid_seq
| sequence pg_dist_shardid_seq
| table citus.pg_dist_object
| table pg_dist_authinfo
| table pg_dist_colocation
| table pg_dist_local_group
| table pg_dist_node
| table pg_dist_node_metadata
| table pg_dist_partition
| table pg_dist_placement
| table pg_dist_poolinfo
| table pg_dist_rebalance_strategy
| table pg_dist_shard
| table pg_dist_transaction
| type citus.distribution_type
| type citus.shard_transfer_mode
| type citus_copy_format
| type noderole
| view citus_dist_stat_activity
| view citus_lock_waits
| view citus_shard_indexes_on_worker
| view citus_shards_on_worker
| view citus_stat_statements
| view citus_worker_stat_activity
| view pg_dist_shard_placement
(188 rows)
-- Test downgrade to 9.2-2 from 9.2-4
ALTER EXTENSION citus UPDATE TO '9.2-4';
ALTER EXTENSION citus UPDATE TO '9.2-2';
-- Should be empty result since upgrade+downgrade should be a no-op
SELECT * FROM print_extension_changes();
previous_object | current_object
---------------------------------------------------------------------
(0 rows)
/*
* As we mistakenly bumped schema version to 9.3-1 (in previous
* release), we support updating citus schema from 9.3-1 to 9.2-4,
* but we do not support explicitly updating it to to 9.3-1.
* Hence below update (to 9.3-1) command should fail.
* As we mistakenly bumped schema version to 9.3-1 in a bad release, we support
* updating citus schema from 9.3-1 to 9.2-4, but we do not support updates to 9.3-1.
*
* Hence the query below should fail.
*/
ALTER EXTENSION citus UPDATE TO '9.3-1';
ERROR: extension "citus" has no update path from version "9.2-4" to version "9.3-1"
ERROR: extension "citus" has no update path from version "9.2-2" to version "9.3-1"
ALTER EXTENSION citus UPDATE TO '9.2-4';
-- Snapshot of state at 9.2-4
SELECT * FROM print_extension_changes();
previous_object | current_object
---------------------------------------------------------------------
(0 rows)
-- Test downgrade to 9.2-4 from 9.3-2
ALTER EXTENSION citus UPDATE TO '9.3-2';
ALTER EXTENSION citus UPDATE TO '9.2-4';
-- Should be empty result since upgrade+downgrade should be a no-op
SELECT * FROM print_extension_changes();
previous_object | current_object
---------------------------------------------------------------------
(0 rows)
-- Snapshot of state at 9.3-2
ALTER EXTENSION citus UPDATE TO '9.3-2';
SELECT * FROM print_extension_changes();
previous_object | current_object
---------------------------------------------------------------------
| function citus_remote_connection_stats()
| function replicate_reference_tables()
| function truncate_local_data_after_distributing_table(regclass)
| function update_distributed_table_colocation(regclass,text)
| function worker_create_or_alter_role(text,text,text)
(5 rows)
DROP TABLE prev_objects, extension_diff;
-- show running version
SHOW citus.version;
citus.version
---------------------------------------------------------------------
9.3devel
9.3.4
(1 row)
-- ensure no objects were created outside pg_catalog

View File

@ -379,7 +379,7 @@ RESET ROLE;
SELECT create_distributed_table('my_table_with_data', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.my_table_with_data$$)
create_distributed_table
---------------------------------------------------------------------
@ -409,7 +409,7 @@ SET ROLE read_access;
SELECT create_distributed_table('my_role_table_with_data', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.my_role_table_with_data$$)
create_distributed_table
---------------------------------------------------------------------
@ -568,7 +568,7 @@ RESET ROLE;
SELECT create_distributed_table('full_access_user_schema.t1', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$full_access_user_schema.t1$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -27,11 +27,11 @@ INSERT INTO partitioning_test_2010 VALUES (4, '2010-03-03');
SELECT create_distributed_table('partitioning_test', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2009$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2010$$)
create_distributed_table
---------------------------------------------------------------------
@ -141,7 +141,7 @@ INSERT INTO partitioning_test_2012 VALUES (6, '2012-07-07');
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2012 FOR VALUES FROM ('2012-01-01') TO ('2013-01-01');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2012$$)
-- see from MX node, attached partition is distributed as well
\c - - - :worker_1_port

View File

@ -29,11 +29,11 @@ INSERT INTO partitioning_hash_test VALUES (4, 4);
SELECT create_distributed_table('partitioning_test', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2009$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2010$$)
create_distributed_table
---------------------------------------------------------------------
@ -43,11 +43,11 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('partitioning_hash_test', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_hash_test_0$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_hash_test_1$$)
create_distributed_table
---------------------------------------------------------------------
@ -170,7 +170,7 @@ INSERT INTO partitioning_test_2012 VALUES (6, '2012-07-07');
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2012 FOR VALUES FROM ('2012-01-01') TO ('2013-01-01');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2012$$)
-- attached partition is distributed as well
SELECT
@ -215,7 +215,7 @@ INSERT INTO partitioning_hash_test_2 VALUES (8, 5);
ALTER TABLE partitioning_hash_test ATTACH PARTITION partitioning_hash_test_2 FOR VALUES WITH (MODULUS 3, REMAINDER 2);
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_hash_test_2$$)
INSERT INTO partitioning_hash_test VALUES (9, 12);
-- see the data is loaded to shards
@ -711,7 +711,7 @@ INSERT INTO partitioning_test_reference SELECT a, a FROM generate_series(1, 50)
SELECT create_reference_table('partitioning_test_reference');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_reference$$)
create_reference_table
---------------------------------------------------------------------

View File

@ -363,9 +363,189 @@ EXECUTE coerce_numeric_2(1);
1 | test value
(1 row)
-- Test that we can insert an integer literal into a numeric column as well
CREATE TABLE numeric_test (id numeric(6, 1), val int);
SELECT create_distributed_table('numeric_test', 'id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
INSERT INTO numeric_test VALUES (21, 87) RETURNING *;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21::int;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21::bigint;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21.0;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21.0::numeric;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
PREPARE insert_p(int) AS INSERT INTO numeric_test VALUES ($1, 87) RETURNING *;
EXECUTE insert_p(1);
id | val
---------------------------------------------------------------------
1.0 | 87
(1 row)
EXECUTE insert_p(2);
id | val
---------------------------------------------------------------------
2.0 | 87
(1 row)
EXECUTE insert_p(3);
id | val
---------------------------------------------------------------------
3.0 | 87
(1 row)
EXECUTE insert_p(4);
id | val
---------------------------------------------------------------------
4.0 | 87
(1 row)
EXECUTE insert_p(5);
id | val
---------------------------------------------------------------------
5.0 | 87
(1 row)
EXECUTE insert_p(6);
id | val
---------------------------------------------------------------------
6.0 | 87
(1 row)
PREPARE select_p(int) AS SELECT * FROM numeric_test WHERE id=$1;
EXECUTE select_p(1);
id | val
---------------------------------------------------------------------
1.0 | 87
(1 row)
EXECUTE select_p(2);
id | val
---------------------------------------------------------------------
2.0 | 87
(1 row)
EXECUTE select_p(3);
id | val
---------------------------------------------------------------------
3.0 | 87
(1 row)
EXECUTE select_p(4);
id | val
---------------------------------------------------------------------
4.0 | 87
(1 row)
EXECUTE select_p(5);
id | val
---------------------------------------------------------------------
5.0 | 87
(1 row)
EXECUTE select_p(6);
id | val
---------------------------------------------------------------------
6.0 | 87
(1 row)
SET citus.enable_fast_path_router_planner TO false;
EXECUTE select_p(1);
id | val
---------------------------------------------------------------------
1.0 | 87
(1 row)
EXECUTE select_p(2);
id | val
---------------------------------------------------------------------
2.0 | 87
(1 row)
EXECUTE select_p(3);
id | val
---------------------------------------------------------------------
3.0 | 87
(1 row)
EXECUTE select_p(4);
id | val
---------------------------------------------------------------------
4.0 | 87
(1 row)
EXECUTE select_p(5);
id | val
---------------------------------------------------------------------
5.0 | 87
(1 row)
EXECUTE select_p(6);
id | val
---------------------------------------------------------------------
6.0 | 87
(1 row)
-- make sure that we don't return wrong resuls
INSERT INTO numeric_test VALUES (21.1, 87) RETURNING *;
id | val
---------------------------------------------------------------------
21.1 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21::numeric;
id | val
---------------------------------------------------------------------
21.0 | 87
(1 row)
SELECT * FROM numeric_test WHERE id = 21.1::numeric;
id | val
---------------------------------------------------------------------
21.1 | 87
(1 row)
SET search_path TO public;
DROP SCHEMA prune_shard_list CASCADE;
NOTICE: drop cascades to 9 other objects
NOTICE: drop cascades to 10 other objects
DETAIL: drop cascades to function prune_shard_list.prune_using_no_values(regclass)
drop cascades to function prune_shard_list.prune_using_single_value(regclass,text)
drop cascades to function prune_shard_list.prune_using_either_value(regclass,text,text)
@ -375,3 +555,4 @@ drop cascades to function prune_shard_list.print_sorted_shard_intervals(regclass
drop cascades to table prune_shard_list.pruning
drop cascades to table prune_shard_list.pruning_range
drop cascades to table prune_shard_list.coerce_hash
drop cascades to table prune_shard_list.numeric_test

View File

@ -208,11 +208,11 @@ INSERT INTO partitioning_test VALUES (2, '2010-07-07');
SELECT create_distributed_table('partitioning_test', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_real_time_transaction.partitioning_test_2009$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_real_time_transaction.partitioning_test_2010$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -6,7 +6,7 @@ INSERT INTO reference_table_test VALUES (1, 1.0, '1', '2016-12-01');
SELECT create_reference_table('reference_table_test');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.reference_table_test$$)
create_reference_table
---------------------------------------------------------------------
@ -1639,6 +1639,15 @@ ORDER BY 1;
-> Seq Scan on colocated_table_test_1250005 colocated_table_test
(25 rows)
WITH a as (SELECT rt.value_2 FROM reference_table_test rt where rt.value_2 = 2)
SELECT ct.value_1, count(*) FROM colocated_table_test ct join a on ct.value_1 = a.value_2
WHERE exists (select * from a)
GROUP BY 1 ORDER BY 1;
value_1 | count
---------------------------------------------------------------------
2 | 5
(1 row)
-- clean up tables, ...
SET client_min_messages TO ERROR;
DROP SEQUENCE example_ref_value_seq;

View File

@ -228,7 +228,7 @@ INSERT INTO tt1 VALUES (1,11), (3,15), (5,17), (6,19), (8,17), (2,12);
SELECT create_distributed_table('tt1','id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.tt1_1120$$)
create_distributed_table
---------------------------------------------------------------------
@ -345,7 +345,7 @@ INSERT INTO test_table_1 VALUES(3, '2111-01-12 08:35:19', 9);
SELECT create_distributed_table('test_table_1', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.test_table_1$$)
create_distributed_table
---------------------------------------------------------------------
@ -800,7 +800,7 @@ INSERT INTO test_table_2 VALUES(3, random());
SELECT create_distributed_table('test_table_2', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.test_table_2$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -413,7 +413,7 @@ DEBUG: generating subplan XXX_1 for subquery SELECT user_id, (random() OPERATOR
DEBUG: Creating router plan
DEBUG: Plan is router executable
DEBUG: generating subplan XXX_2 for subquery SELECT sub1.id, (random() OPERATOR(pg_catalog.*) (0)::double precision) FROM (SELECT users_ref_test_table.id FROM public.users_ref_test_table) sub1 UNION SELECT intermediate_result.user_id, intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, "?column?" double precision)
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT id, "?column?" FROM (SELECT intermediate_result.id, intermediate_result."?column?" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id integer, "?column?" double precision)) sub ORDER BY id DESC
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT id, "?column?" FROM (SELECT intermediate_result.id, intermediate_result."?column?" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(id integer, "?column?" double precision)) sub(id, "?column?") ORDER BY id DESC
DEBUG: Creating router plan
DEBUG: Plan is router executable
id | ?column?

View File

@ -1,3 +1,5 @@
CREATE SCHEMA multi_subtransactions;
SET search_path TO 'multi_subtransactions';
CREATE TABLE artists (
id bigint NOT NULL,
name text NOT NULL
@ -159,7 +161,7 @@ BEGIN;
DELETE FROM artists;
SAVEPOINT s1;
INSERT INTO artists SELECT NULL, NULL FROM generate_series(1, 5) i;
ERROR: the partition column of table public.artists cannot be NULL
ERROR: the partition column of table multi_subtransactions.artists cannot be NULL
ROLLBACK TO s1;
INSERT INTO artists VALUES (11, 'Egon Schiele');
COMMIT;
@ -175,7 +177,7 @@ BEGIN;
DELETE FROM artists;
SAVEPOINT s1;
INSERT INTO artists(name) SELECT 'a' FROM generate_series(1, 5) i;
ERROR: the partition column of table public.artists should have a value
ERROR: the partition column of table multi_subtransactions.artists should have a value
ROLLBACK TO s1;
INSERT INTO artists VALUES (12, 'Marc Chagall');
COMMIT;
@ -401,6 +403,29 @@ SELECT * FROM researchers WHERE lab_id=10;
32 | 10 | Raymond Smullyan
(2 rows)
-- Verify that we don't have a memory leak in subtransactions
-- See https://github.com/citusdata/citus/pull/4000
CREATE FUNCTION text2number(v_value text) RETURNS numeric
LANGUAGE plpgsql VOLATILE
AS $$
BEGIN
RETURN v_value::numeric;
exception
when others then
return null;
END;
$$;
-- if we leak at least an integer in each subxact, then size of TopTransactionSize
-- will be way beyond the 50k limit. If issue #3999 happens, then this will also take
-- a long time, since for each row we will create a memory context that is not destroyed
-- until the end of command.
SELECT max(text2number('1234')), max(public.top_transaction_context_size()) > 50000 AS leaked
FROM generate_series(1, 20000);
max | leaked
---------------------------------------------------------------------
1234 | f
(1 row)
-- Clean-up
DROP TABLE artists;
DROP TABLE researchers;
SET client_min_messages TO ERROR;
DROP SCHEMA multi_subtransactions CASCADE;

View File

@ -49,3 +49,7 @@ CREATE OR REPLACE FUNCTION pg_catalog.partition_task_list_results(resultIdPrefix
targetShardIndex int)
LANGUAGE C STRICT VOLATILE
AS 'citus', $$partition_task_list_results$$;
-- get size of TopTransactionContext
CREATE OR REPLACE FUNCTION top_transaction_context_size() RETURNS BIGINT
LANGUAGE C STRICT VOLATILE
AS 'citus', $$top_transaction_context_size$$;

View File

@ -308,7 +308,7 @@ INSERT INTO test_local_truncate VALUES (1,2);
SELECT create_distributed_table('test_local_truncate', 'x', colocate_with => 'none');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_truncate.test_local_truncate$$)
create_distributed_table
---------------------------------------------------------------------
@ -347,7 +347,7 @@ INSERT INTO test_local_truncate VALUES (1,2);
SELECT create_distributed_table('test_local_truncate', 'x', colocate_with => 'none');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_truncate.test_local_truncate$$)
create_distributed_table
---------------------------------------------------------------------
@ -395,7 +395,7 @@ DETAIL: This UDF only truncates local records of distributed tables.
SELECT create_distributed_table('referenced_table', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_truncate.referenced_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -410,7 +410,7 @@ DETAIL: Table "referencing_table" references "referenced_table"
SELECT create_distributed_table('referencing_table', 'ref_id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_truncate.referencing_table$$)
create_distributed_table
---------------------------------------------------------------------
@ -485,7 +485,7 @@ INSERT INTO ref SELECT x,x FROM generate_series(1,10000) x;
SELECT create_reference_table('ref');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_truncate.ref$$)
create_reference_table
---------------------------------------------------------------------
@ -525,7 +525,7 @@ INSERT INTO t1 VALUES(1,1);
SELECT create_distributed_table('t1', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$multi_truncate.t1$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -37,7 +37,7 @@ insert into gen2 (id, val1) values (1,4),(3,6),(5,2),(7,2);
select create_distributed_table('gen1', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_pg12.gen1$$)
create_distributed_table
---------------------------------------------------------------------
@ -47,6 +47,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
select create_distributed_table('gen2', 'val2');
ERROR: cannot distribute relation: gen2
DETAIL: Distribution column must not use GENERATED ALWAYS AS (...) STORED.
copy gen1 to :'temp_dir''pg12_copy_test_generated';
insert into gen1 (id, val1) values (2,4),(4,6),(6,2),(8,2);
insert into gen2 (id, val1) values (2,4),(4,6),(6,2),(8,2);
select * from gen1 order by 1,2,3;
@ -75,6 +76,17 @@ select * from gen2 order by 1,2,3;
8 | 2 | 4
(8 rows)
truncate gen1;
copy gen1 from :'temp_dir''pg12_copy_test_generated';
select * from gen1 order by 1,2,3;
id | val2 | val1
---------------------------------------------------------------------
1 | 6 | 4
3 | 8 | 6
5 | 4 | 2
7 | 4 | 2
(4 rows)
-- Test new VACUUM/ANALYZE options
analyze (skip_locked) gen1;
vacuum (skip_locked) gen1;
@ -271,7 +283,7 @@ DETAIL: Key (key, collection_id)=(1, 1000) is not present in table "collections
SELECT create_distributed_table('collections_list', 'key');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_pg12.collections_list_0$$)
create_distributed_table
---------------------------------------------------------------------
@ -281,7 +293,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('collection_users', 'key');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_pg12.collection_users$$)
create_distributed_table
---------------------------------------------------------------------
@ -302,7 +314,7 @@ INSERT INTO test (x,y) SELECT i,i*3 from generate_series(1, 100) i;
SELECT create_distributed_table('test', 'x');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_pg12.test$$)
create_distributed_table
---------------------------------------------------------------------
@ -392,7 +404,7 @@ ERROR: Hash distributed partition columns may not use a non deterministic colla
select create_distributed_table('col_test', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_pg12.col_test$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -59,7 +59,7 @@ drop cascades to table "weird.table"
SELECT create_distributed_table('data', 'key');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$dumper.data$$)
create_distributed_table
---------------------------------------------------------------------
@ -69,7 +69,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('"weird.table"', 'key,');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$dumper."weird.table"$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -972,7 +972,7 @@ BEGIN;
SELECT create_distributed_table('table_3', 'key');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$access_tracking.table_3$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -28,11 +28,11 @@ INSERT INTO collections (key, ts, collection_id, value) VALUES (4, '2009-01-01',
SELECT create_distributed_table('collections', 'key');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$partitioned_table_replicated.collections_1$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$partitioned_table_replicated.collections_2$$)
create_distributed_table
---------------------------------------------------------------------
@ -48,7 +48,7 @@ INSERT INTO collections_4 SELECT i, '2009-01-01', 4, i FROM generate_series (0,
ALTER TABLE collections ATTACH PARTITION collections_4 FOR VALUES IN ( 4 );
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$partitioned_table_replicated.collections_4$$)
-- finally attach a distributed table to a distributed table
CREATE TABLE collections_5 AS SELECT * FROM collections LIMIT 0;

View File

@ -294,7 +294,7 @@ INSERT INTO test_seq_truncate SELECT i FROM generate_series(0, 100) i;
SELECT create_distributed_table('test_seq_truncate', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_seq_ddl.test_seq_truncate$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -0,0 +1,151 @@
-- setup schema used for sqlsmith runs
-- source: https://gist.github.com/will/e8a1e6efd46ac82f1b61d0c0ccab1b52
CREATE SCHEMA sqlsmith_failures;
SET search_path TO sqlsmith_failures, public;
SET citus.shard_replication_factor TO 1;
SET citus.next_shard_id TO 1280000;
SHOW server_version \gset
SELECT substring(:'server_version', '\d+')::int > 11 AS server_version_above_eleven
\gset
begin;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
create table countries(
id serial primary key
, name text
, code varchar(2) collate "C" unique
);
insert into countries(name, code) select 'country-'||i, i::text from generate_series(10,99) i;
select create_reference_table('countries');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$sqlsmith_failures.countries$$)
create_reference_table
---------------------------------------------------------------------
(1 row)
create table orgs (
id bigserial primary key
, name text
, created_at timestamptz default now()
);
select create_distributed_table('orgs', 'id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
\if :server_version_above_eleven
-- pg12 and above support generated columns
create table users (
id bigserial
, org_id bigint references orgs(id)
, name text
, created_at timestamptz default now()
, country_id int -- references countries(id)
, score bigint generated always as (id + country_id) stored
, primary key (org_id, id)
);
\else
-- pg11 and below don't have generated columns, use a normal column
create table users (
id bigserial
, org_id bigint references orgs(id)
, name text
, created_at timestamptz default now()
, country_id int -- references countries(id)
, score bigint
, primary key (org_id, id)
);
\endif
select create_distributed_table('users', 'org_id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
alter table users add constraint fk_user_country foreign key (country_id) references countries(id);
create table orders (
id bigserial
, org_id bigint references orgs(id)
, user_id bigint
, price int
, info jsonb
, primary key (org_id, id)
, foreign key (org_id, user_id) references users(org_id, id)
);
select create_distributed_table('orders', 'org_id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
create table events (
id bigserial not null
, user_id bigint not null
, org_id bigint not null
, event_time timestamp not null default now()
, event_type int not null default 0
, payload jsonb
, primary key (user_id, id)
);
create index event_time_idx on events using BRIN (event_time);
create index event_json_idx on events using gin(payload);
select create_distributed_table('events', 'user_id'); -- on purpose don't collocate on correctly on org_id
create_distributed_table
---------------------------------------------------------------------
(1 row)
create table local_data(
id bigserial primary key
, val int default ( (random()*100)::int )
);
-- data loading takes ~30 seconds, lets hope we can skip this for all reproductions. When
-- there is a sqlsmith failure that needs the data we can uncomment the block below.
-- insert into orgs(id, name) select i,'org-'||i from generate_series(1,1000) i;
-- insert into users(id, name, org_id, country_id) select i,'user-'||i, i%1000+1, (i%90)+1 from generate_series(1,100000) i;
-- insert into orders(id, org_id, user_id, price) select i, ((i%100000+1)%1000)+1 , i%100000+1, i/100 from generate_series(1,1000000) i;
-- insert into events(id, org_id, user_id, event_type) select i, ((i%100000+1)%1000)+1 , i%100000+1, i/100 from generate_series(1,1000000) i;
-- insert into local_data(id) select generate_series(1,1000);
commit;
-- SQL SMITH ASSERTION FAILURE https://github.com/citusdata/citus/issues/3809
-- Root cause: pruned worker columns not projected correctly on coordinator causing an assertion in the postgres standard planner
select
case when pg_catalog.bit_or(cast(cast(coalesce(cast(null as "bit"), cast(null as "bit")) as "bit") as "bit")) over (partition by subq_0.c3 order by subq_0.c0) <> cast(null as "bit")
then subq_0.c3
else subq_0.c3
end as c0,
30 as c1,
subq_0.c2 as c2
from
(select
pg_catalog.websearch_to_tsquery(
cast(pg_catalog.regconfigin(cast(cast(null as cstring) as cstring)) as regconfig),
cast((select type from citus.pg_dist_object limit 1 offset 1) as text)
) as c0,
sample_0.org_id as c1,
sample_0.id as c2,
sample_0.score as c3,
sample_0.country_id as c4,
sample_0.org_id as c5,
sample_0.org_id as c6
from
sqlsmith_failures.users as sample_0 tablesample system (7.5)
where sample_0.org_id is not NULL) as subq_0
where (select pg_catalog.array_agg(id) from sqlsmith_failures.countries)
is not NULL;
c0 | c1 | c2
---------------------------------------------------------------------
(0 rows)
-- cleanup
DROP SCHEMA sqlsmith_failures CASCADE;
NOTICE: drop cascades to 6 other objects
DETAIL: drop cascades to table countries
drop cascades to table orgs
drop cascades to table users
drop cascades to table orders
drop cascades to table events
drop cascades to table local_data

View File

@ -509,6 +509,62 @@ GROUP BY a.key ORDER BY 3, 2, 1;
key-1 | (key-1,value-2,"Wed Jan 01 00:00:00 2020") | 1
(2 rows)
-- Of the target list entries, v1-v3 should be wrapped in any_value as they do
-- not appear in GROUP BY. The append happens on the coordinator in that case.
-- Vars in the HAVING that do not appear in the GROUP BY are also wrapped.
SELECT
a.key as k1,
a.key as k2,
a.key || '_append' as k3,
a.value as v1,
a.value as v2,
a.value || '_notgrouped' as v3,
a.value || '_append' as va1,
a.value || '_append' as va2,
a.value || '_append' || '_more' as va2,
count(*)
FROM items a LEFT JOIN other_items b ON (a.key = b.key)
GROUP BY a.key, a.value ||'_append'
HAVING length(a.key) + length(a.value) < length(a.value || '_append')
ORDER BY 1;
k1 | k2 | k3 | v1 | v2 | v3 | va1 | va2 | va2 | count
---------------------------------------------------------------------
key-1 | key-1 | key-1_append | value-2 | value-2 | value-2_notgrouped | value-2_append | value-2_append | value-2_append_more | 1
key-2 | key-2 | key-2_append | value-1 | value-1 | value-1_notgrouped | value-1_append | value-1_append | value-1_append_more | 1
(2 rows)
SELECT coordinator_plan($$
EXPLAIN (VERBOSE ON, COSTS OFF)
SELECT
a.key as k1,
a.key as k2,
a.key || '_append' as k3,
a.value as v1,
a.value as v2,
a.value || '_notgrouped' as v3,
a.value || '_append' as va1,
a.value || '_append' as va2,
a.value || '_append' || '_more' as va3,
count(*)
FROM items a LEFT JOIN other_items b ON (a.key = b.key)
GROUP BY a.key, a.value ||'_append'
HAVING length(a.key) + length(a.value) < length(a.value || '_append')
ORDER BY 1
$$);
coordinator_plan
---------------------------------------------------------------------
Sort
Output: remote_scan.k1, remote_scan.k2, remote_scan.k3, (any_value(remote_scan.v1)), (any_value(remote_scan.v2)), ((any_value(remote_scan.v3) || '_notgrouped'::text)), remote_scan.va1, remote_scan.va2, remote_scan.va3, (COALESCE((pg_catalog.sum(remote_scan.count))::bigint, '0'::bigint))
Sort Key: remote_scan.k1
-> HashAggregate
Output: remote_scan.k1, remote_scan.k2, remote_scan.k3, any_value(remote_scan.v1), any_value(remote_scan.v2), (any_value(remote_scan.v3) || '_notgrouped'::text), remote_scan.va1, remote_scan.va2, remote_scan.va3, COALESCE((pg_catalog.sum(remote_scan.count))::bigint, '0'::bigint)
Group Key: remote_scan.k1, remote_scan.va1
Filter: ((length(remote_scan.worker_column_11) + length(any_value(remote_scan.worker_column_12))) < length((any_value(remote_scan.worker_column_13) || '_append'::text)))
-> Custom Scan (Citus Adaptive)
Output: remote_scan.k1, remote_scan.k2, remote_scan.k3, remote_scan.v1, remote_scan.v2, remote_scan.v3, remote_scan.va1, remote_scan.va2, remote_scan.va3, remote_scan.count, remote_scan.worker_column_11, remote_scan.worker_column_12, remote_scan.worker_column_13
Task Count: 4
(10 rows)
SELECT a FROM items a ORDER BY key;
a
---------------------------------------------------------------------

View File

@ -19,11 +19,11 @@ SET citus.shard_replication_factor TO 1;
SELECT create_distributed_table('partitioning_test', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$subquery_and_partitioning.partitioning_test_2010$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$subquery_and_partitioning.partitioning_test_2017$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -0,0 +1,651 @@
--
-- TDIGEST_AGGREGATE_SUPPORT
-- test the integration of github.com/tvondra/tdigest aggregates into the citus planner
-- for push down parts of the aggregate to use parallelized execution and reduced data
-- transfer sizes for aggregates not grouped by the distribution column
--
SET citus.next_shard_id TO 20070000;
CREATE SCHEMA tdigest_aggregate_support;
SET search_path TO tdigest_aggregate_support, public;
-- create the tdigest extension when installed
SELECT CASE WHEN COUNT(*) > 0
THEN 'CREATE EXTENSION tdigest WITH SCHEMA public'
ELSE 'SELECT false AS tdigest_present' END
AS create_cmd FROM pg_available_extensions()
WHERE name = 'tdigest'
\gset
:create_cmd;
SET citus.shard_count TO 4;
SET citus.coordinator_aggregation_strategy TO 'disabled'; -- prevent aggregate execution when the aggregate can't be pushed down
CREATE TABLE latencies (a int, b int, latency double precision);
SELECT create_distributed_table('latencies', 'a');
create_distributed_table
---------------------------------------------------------------------
(1 row)
SELECT setseed(0.42); -- make the random data inserted deterministic
setseed
---------------------------------------------------------------------
(1 row)
INSERT INTO latencies
SELECT (random()*20)::int AS a,
(random()*20)::int AS b,
random()*10000.0 AS latency
FROM generate_series(1, 10000);
-- explain no grouping to verify partially pushed down for tdigest(value, compression)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest(latency, 100)
FROM latencies;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest(remote_scan.tdigest)
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(latency, 100) AS tdigest FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(latency, 100)
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest(value, compression)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest(latency, 100)
FROM latencies
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest(latency, 100) AS tdigest FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest(latency, 100)
Group Key: latencies.a
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(12 rows)
-- explain grouping by non-distribution column is partially pushed down for tdigest(value, compression)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest(latency, 100)
FROM latencies
GROUP BY b;
QUERY PLAN
---------------------------------------------------------------------
HashAggregate
Output: remote_scan.b, tdigest(remote_scan.tdigest)
Group Key: remote_scan.b
-> Custom Scan (Citus Adaptive)
Output: remote_scan.b, remote_scan.tdigest
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT b, public.tdigest(latency, 100) AS tdigest FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY b
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: b, tdigest(latency, 100)
Group Key: latencies.b
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(15 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile(value, compression, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(latency, 100, 0.99)
FROM latencies;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile(remote_scan.tdigest_percentile, '0.99'::double precision)
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(latency, 100) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(latency, 100)
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(value, compression, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(latency, 100, 0.99)
FROM latencies
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile(latency, 100, '0.99'::double precision) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile(latency, 100, '0.99'::double precision)
Group Key: latencies.a
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(12 rows)
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile(value, compression, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile(latency, 100, 0.99)
FROM latencies
GROUP BY b;
QUERY PLAN
---------------------------------------------------------------------
HashAggregate
Output: remote_scan.b, tdigest_percentile(remote_scan.tdigest_percentile, '0.99'::double precision)
Group Key: remote_scan.b
-> Custom Scan (Citus Adaptive)
Output: remote_scan.b, remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT b, public.tdigest(latency, 100) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY b
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: b, tdigest(latency, 100)
Group Key: latencies.b
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(15 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(latency, 100, ARRAY[0.99, 0.95])
FROM latencies;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile(remote_scan.tdigest_percentile, '{0.99,0.95}'::double precision[])
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(latency, 100) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(latency, 100)
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(latency, 100, ARRAY[0.99, 0.95])
FROM latencies
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile(latency, 100, '{0.99,0.95}'::double precision[]) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile(latency, 100, '{0.99,0.95}'::double precision[])
Group Key: latencies.a
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(12 rows)
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile(latency, 100, ARRAY[0.99, 0.95])
FROM latencies
GROUP BY b;
QUERY PLAN
---------------------------------------------------------------------
HashAggregate
Output: remote_scan.b, tdigest_percentile(remote_scan.tdigest_percentile, '{0.99,0.95}'::double precision[])
Group Key: remote_scan.b
-> Custom Scan (Citus Adaptive)
Output: remote_scan.b, remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT b, public.tdigest(latency, 100) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY b
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: b, tdigest(latency, 100)
Group Key: latencies.b
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(15 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(latency, 100, 9000)
FROM latencies;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile_of(remote_scan.tdigest_percentile_of, '9000'::double precision)
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(latency, 100) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(latency, 100)
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(latency, 100, 9000)
FROM latencies
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile_of(latency, 100, '9000'::double precision) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile_of(latency, 100, '9000'::double precision)
Group Key: latencies.a
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(12 rows)
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile_of(latency, 100, 9000)
FROM latencies
GROUP BY b;
QUERY PLAN
---------------------------------------------------------------------
HashAggregate
Output: remote_scan.b, tdigest_percentile_of(remote_scan.tdigest_percentile_of, '9000'::double precision)
Group Key: remote_scan.b
-> Custom Scan (Citus Adaptive)
Output: remote_scan.b, remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT b, public.tdigest(latency, 100) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY b
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: b, tdigest(latency, 100)
Group Key: latencies.b
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(15 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(latency, 100, ARRAY[9000, 9500])
FROM latencies;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile_of(remote_scan.tdigest_percentile_of, '{9000,9500}'::double precision[])
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(latency, 100) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(latency, 100)
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(latency, 100, ARRAY[9000, 9500])
FROM latencies
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile_of(latency, 100, '{9000,9500}'::double precision[]) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile_of(latency, 100, '{9000,9500}'::double precision[])
Group Key: latencies.a
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(12 rows)
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile_of(latency, 100, ARRAY[9000, 9500])
FROM latencies
GROUP BY b;
QUERY PLAN
---------------------------------------------------------------------
HashAggregate
Output: remote_scan.b, tdigest_percentile_of(remote_scan.tdigest_percentile_of, '{9000,9500}'::double precision[])
Group Key: remote_scan.b
-> Custom Scan (Citus Adaptive)
Output: remote_scan.b, remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT b, public.tdigest(latency, 100) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_20070000 latencies WHERE true GROUP BY b
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: b, tdigest(latency, 100)
Group Key: latencies.b
-> Seq Scan on tdigest_aggregate_support.latencies_20070000 latencies
Output: a, b, latency
(15 rows)
-- verifying results - should be stable due to seed while inserting the data, if failure due to data these queries could be removed or check for certain ranges
SELECT tdigest(latency, 100) FROM latencies;
tdigest
---------------------------------------------------------------------
flags 0 count 10000 compression 100 centroids 46 (0.287235, 1) (1.025106, 1) (2.058216, 1) (5.335597, 1) (12.707263, 2) (25.302479, 3) (43.435063, 4) (77.987860, 5) (269.478664, 10) (509.417419, 13) (1227.158879, 22) (3408.256171, 35) (7772.721988, 55) (13840.275516, 65) (32937.127607, 108) (64476.403332, 148) (118260.230644, 199) (239584.293240, 292) (562119.836766, 463) (944722.686313, 547) (1751089.620493, 749) (3751264.745959, 1128) (5877270.108576, 1300) (6224557.402567, 1104) (5804999.258033, 874) (5632316.697114, 755) (4648651.050740, 573) (3460055.227950, 402) (2820271.404686, 314) (2676501.012955, 288) (1649845.166017, 173) (1269335.942008, 131) (813964.853243, 83) (484144.878702, 49) (337179.763016, 34) (198775.241901, 20) (149353.499704, 15) (109688.319223, 11) (79855.926155, 8) (49937.731689, 5) (29971.046175, 3) (19982.538737, 2) (9991.467422, 1) (9992.337047, 1) (9995.578357, 1) (9999.700339, 1)
(1 row)
SELECT tdigest_percentile(latency, 100, 0.99) FROM latencies;
tdigest_percentile
---------------------------------------------------------------------
9904.28342426494
(1 row)
SELECT tdigest_percentile(latency, 100, ARRAY[0.99, 0.95]) FROM latencies;
tdigest_percentile
---------------------------------------------------------------------
{9904.28342426494,9485.49009399385}
(1 row)
SELECT tdigest_percentile_of(latency, 100, 9000) FROM latencies;
tdigest_percentile_of
---------------------------------------------------------------------
0.903462047211138
(1 row)
SELECT tdigest_percentile_of(latency, 100, ARRAY[9000, 9500]) FROM latencies;
tdigest_percentile_of
---------------------------------------------------------------------
{0.903462047211138,0.95137481812975}
(1 row)
CREATE TABLE latencies_rollup (a int, tdigest tdigest);
SELECT create_distributed_table('latencies_rollup', 'a', colocate_with => 'latencies');
create_distributed_table
---------------------------------------------------------------------
(1 row)
INSERT INTO latencies_rollup
SELECT a, tdigest(latency, 100)
FROM latencies
GROUP BY a;
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest(tdigest)
FROM latencies_rollup;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest(remote_scan.tdigest)
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(tdigest) AS tdigest FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(tdigest)
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest(tdigest)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest(tdigest)
FROM latencies_rollup
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest(tdigest) AS tdigest FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest(tdigest)
Group Key: latencies_rollup.a
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(12 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile(tdigest, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(tdigest, 0.99)
FROM latencies_rollup;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile(remote_scan.tdigest_percentile, '0.99'::double precision)
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(tdigest) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(tdigest)
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(tdigest, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(tdigest, 0.99)
FROM latencies_rollup
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile(tdigest, '0.99'::double precision) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile(tdigest, '0.99'::double precision)
Group Key: latencies_rollup.a
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(12 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(tdigest, ARRAY[0.99, 0.95])
FROM latencies_rollup;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile(remote_scan.tdigest_percentile, '{0.99,0.95}'::double precision[])
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(tdigest) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(tdigest)
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(tdigest, ARRAY[0.99, 0.95])
FROM latencies_rollup
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile(tdigest, '{0.99,0.95}'::double precision[]) AS tdigest_percentile FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile(tdigest, '{0.99,0.95}'::double precision[])
Group Key: latencies_rollup.a
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(12 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(tdigest, 9000)
FROM latencies_rollup;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile_of(remote_scan.tdigest_percentile_of, '9000'::double precision)
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(tdigest) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(tdigest)
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(tdigest, 9000)
FROM latencies_rollup
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile_of(tdigest, '9000'::double precision) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile_of(tdigest, '9000'::double precision)
Group Key: latencies_rollup.a
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(12 rows)
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(tdigest, ARRAY[9000, 9500])
FROM latencies_rollup;
QUERY PLAN
---------------------------------------------------------------------
Aggregate
Output: tdigest_percentile_of(remote_scan.tdigest_percentile_of, '{9000,9500}'::double precision[])
-> Custom Scan (Citus Adaptive)
Output: remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT public.tdigest(tdigest) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true
Node: host=localhost port=xxxxx dbname=regression
-> Aggregate
Output: tdigest(tdigest)
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(13 rows)
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(tdigest, ARRAY[9000, 9500])
FROM latencies_rollup
GROUP BY a;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (Citus Adaptive)
Output: remote_scan.a, remote_scan.tdigest_percentile_of
Task Count: 4
Tasks Shown: One of 4
-> Task
Query: SELECT a, public.tdigest_percentile_of(tdigest, '{9000,9500}'::double precision[]) AS tdigest_percentile_of FROM tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup WHERE true GROUP BY a
Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate
Output: a, tdigest_percentile_of(tdigest, '{9000,9500}'::double precision[])
Group Key: latencies_rollup.a
-> Seq Scan on tdigest_aggregate_support.latencies_rollup_20070004 latencies_rollup
Output: a, tdigest
(12 rows)
-- verifying results - should be stable due to seed while inserting the data, if failure due to data these queries could be removed or check for certain ranges
SELECT tdigest(tdigest) FROM latencies_rollup;
tdigest
---------------------------------------------------------------------
flags 0 count 10000 compression 100 centroids 47 (0.287235, 1) (1.025106, 1) (2.058216, 1) (5.335597, 1) (12.707263, 2) (25.302479, 3) (43.435063, 4) (77.987860, 5) (241.681030, 9) (402.696604, 11) (999.675875, 20) (2310.848640, 27) (4374.387978, 37) (9722.896547, 56) (21713.805492, 87) (39735.065966, 112) (87335.860853, 177) (182744.906162, 262) (336766.886786, 338) (661263.339724, 464) (1228663.222377, 623) (2146097.038498, 805) (2854487.701653, 827) (5292830.156590, 1195) (6168185.834602, 1104) (6399734.303813, 966) (5778088.854724, 773) (5213381.984997, 637) (3763042.148296, 431) (3036786.646485, 333) (1948238.134602, 207) (1456568.605821, 152) (999888.715345, 103) (715935.892988, 73) (543464.906535, 55) (327339.982973, 33) (198853.838033, 20) (159362.743852, 16) (79807.827301, 8) (69877.414438, 7) (49937.731689, 5) (29971.046175, 3) (19982.538737, 2) (9991.467422, 1) (9992.337047, 1) (9995.578357, 1) (9999.700339, 1)
(1 row)
SELECT tdigest_percentile(tdigest, 0.99) FROM latencies_rollup;
tdigest_percentile
---------------------------------------------------------------------
9903.76070790358
(1 row)
SELECT tdigest_percentile(tdigest, ARRAY[0.99, 0.95]) FROM latencies_rollup;
tdigest_percentile
---------------------------------------------------------------------
{9903.76070790358,9492.7106302226}
(1 row)
SELECT tdigest_percentile_of(tdigest, 9000) FROM latencies_rollup;
tdigest_percentile_of
---------------------------------------------------------------------
0.902852659582396
(1 row)
SELECT tdigest_percentile_of(tdigest, ARRAY[9000, 9500]) FROM latencies_rollup;
tdigest_percentile_of
---------------------------------------------------------------------
{0.902852659582396,0.950865574659141}
(1 row)
SET client_min_messages TO WARNING; -- suppress cascade messages
DROP SCHEMA tdigest_aggregate_support CASCADE;

View File

@ -0,0 +1,234 @@
--
-- TDIGEST_AGGREGATE_SUPPORT
-- test the integration of github.com/tvondra/tdigest aggregates into the citus planner
-- for push down parts of the aggregate to use parallelized execution and reduced data
-- transfer sizes for aggregates not grouped by the distribution column
--
SET citus.next_shard_id TO 20070000;
CREATE SCHEMA tdigest_aggregate_support;
SET search_path TO tdigest_aggregate_support, public;
-- create the tdigest extension when installed
SELECT CASE WHEN COUNT(*) > 0
THEN 'CREATE EXTENSION tdigest WITH SCHEMA public'
ELSE 'SELECT false AS tdigest_present' END
AS create_cmd FROM pg_available_extensions()
WHERE name = 'tdigest'
\gset
:create_cmd;
tdigest_present
---------------------------------------------------------------------
f
(1 row)
SET citus.shard_count TO 4;
SET citus.coordinator_aggregation_strategy TO 'disabled'; -- prevent aggregate execution when the aggregate can't be pushed down
CREATE TABLE latencies (a int, b int, latency double precision);
SELECT create_distributed_table('latencies', 'a');
create_distributed_table
---------------------------------------------------------------------
(1 row)
SELECT setseed(0.42); -- make the random data inserted deterministic
setseed
---------------------------------------------------------------------
(1 row)
INSERT INTO latencies
SELECT (random()*20)::int AS a,
(random()*20)::int AS b,
random()*10000.0 AS latency
FROM generate_series(1, 10000);
-- explain no grouping to verify partially pushed down for tdigest(value, compression)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest(latency, 100)
FROM latencies;
ERROR: function tdigest(double precision, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by distribution column is completely pushed down for tdigest(value, compression)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest(latency, 100)
FROM latencies
GROUP BY a;
ERROR: function tdigest(double precision, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by non-distribution column is partially pushed down for tdigest(value, compression)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest(latency, 100)
FROM latencies
GROUP BY b;
ERROR: function tdigest(double precision, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain no grouping to verify partially pushed down for tdigest_precentile(value, compression, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(latency, 100, 0.99)
FROM latencies;
ERROR: function tdigest_percentile(double precision, integer, numeric) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(value, compression, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(latency, 100, 0.99)
FROM latencies
GROUP BY a;
ERROR: function tdigest_percentile(double precision, integer, numeric) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile(value, compression, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile(latency, 100, 0.99)
FROM latencies
GROUP BY b;
ERROR: function tdigest_percentile(double precision, integer, numeric) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain no grouping to verify partially pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(latency, 100, ARRAY[0.99, 0.95])
FROM latencies;
ERROR: function tdigest_percentile(double precision, integer, numeric[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(latency, 100, ARRAY[0.99, 0.95])
FROM latencies
GROUP BY a;
ERROR: function tdigest_percentile(double precision, integer, numeric[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile(latency, 100, ARRAY[0.99, 0.95])
FROM latencies
GROUP BY b;
ERROR: function tdigest_percentile(double precision, integer, numeric[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(latency, 100, 9000)
FROM latencies;
ERROR: function tdigest_percentile_of(double precision, integer, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(latency, 100, 9000)
FROM latencies
GROUP BY a;
ERROR: function tdigest_percentile_of(double precision, integer, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile_of(latency, 100, 9000)
FROM latencies
GROUP BY b;
ERROR: function tdigest_percentile_of(double precision, integer, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(latency, 100, ARRAY[9000, 9500])
FROM latencies;
ERROR: function tdigest_percentile_of(double precision, integer, integer[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(latency, 100, ARRAY[9000, 9500])
FROM latencies
GROUP BY a;
ERROR: function tdigest_percentile_of(double precision, integer, integer[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- explain grouping by non-distribution column is partially pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT b, tdigest_percentile_of(latency, 100, ARRAY[9000, 9500])
FROM latencies
GROUP BY b;
ERROR: function tdigest_percentile_of(double precision, integer, integer[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- verifying results - should be stable due to seed while inserting the data, if failure due to data these queries could be removed or check for certain ranges
SELECT tdigest(latency, 100) FROM latencies;
ERROR: function tdigest(double precision, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT tdigest_percentile(latency, 100, 0.99) FROM latencies;
ERROR: function tdigest_percentile(double precision, integer, numeric) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT tdigest_percentile(latency, 100, ARRAY[0.99, 0.95]) FROM latencies;
ERROR: function tdigest_percentile(double precision, integer, numeric[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT tdigest_percentile_of(latency, 100, 9000) FROM latencies;
ERROR: function tdigest_percentile_of(double precision, integer, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT tdigest_percentile_of(latency, 100, ARRAY[9000, 9500]) FROM latencies;
ERROR: function tdigest_percentile_of(double precision, integer, integer[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
CREATE TABLE latencies_rollup (a int, tdigest tdigest);
ERROR: type "tdigest" does not exist
SELECT create_distributed_table('latencies_rollup', 'a', colocate_with => 'latencies');
ERROR: relation "latencies_rollup" does not exist
INSERT INTO latencies_rollup
SELECT a, tdigest(latency, 100)
FROM latencies
GROUP BY a;
ERROR: relation "latencies_rollup" does not exist
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest(tdigest)
FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
-- explain grouping by distribution column is completely pushed down for tdigest(tdigest)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest(tdigest)
FROM latencies_rollup
GROUP BY a;
ERROR: relation "latencies_rollup" does not exist
-- explain no grouping to verify partially pushed down for tdigest_precentile(tdigest, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(tdigest, 0.99)
FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(tdigest, quantile)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(tdigest, 0.99)
FROM latencies_rollup
GROUP BY a;
ERROR: relation "latencies_rollup" does not exist
-- explain no grouping to verify partially pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile(tdigest, ARRAY[0.99, 0.95])
FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
-- explain grouping by distribution column is completely pushed down for tdigest_precentile(value, compression, quantiles[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile(tdigest, ARRAY[0.99, 0.95])
FROM latencies_rollup
GROUP BY a;
ERROR: relation "latencies_rollup" does not exist
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(tdigest, 9000)
FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_value)
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(tdigest, 9000)
FROM latencies_rollup
GROUP BY a;
ERROR: relation "latencies_rollup" does not exist
-- explain no grouping to verify partially pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT tdigest_percentile_of(tdigest, ARRAY[9000, 9500])
FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
-- explain grouping by distribution column is completely pushed down for tdigest_precentile_of(value, compression, hypotetical_values[])
EXPLAIN (COSTS OFF, VERBOSE)
SELECT a, tdigest_percentile_of(tdigest, ARRAY[9000, 9500])
FROM latencies_rollup
GROUP BY a;
ERROR: relation "latencies_rollup" does not exist
-- verifying results - should be stable due to seed while inserting the data, if failure due to data these queries could be removed or check for certain ranges
SELECT tdigest(tdigest) FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
SELECT tdigest_percentile(tdigest, 0.99) FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
SELECT tdigest_percentile(tdigest, ARRAY[0.99, 0.95]) FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
SELECT tdigest_percentile_of(tdigest, 9000) FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
SELECT tdigest_percentile_of(tdigest, ARRAY[9000, 9500]) FROM latencies_rollup;
ERROR: relation "latencies_rollup" does not exist
SET client_min_messages TO WARNING; -- suppress cascade messages
DROP SCHEMA tdigest_aggregate_support CASCADE;

View File

@ -208,7 +208,7 @@ SELECT * FROM t2 ORDER BY a;
SELECT create_distributed_table('t2', 'a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$upgrade_basic.t2$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -16,11 +16,11 @@ INSERT INTO partitioning_test_2010 VALUES (4, '2010-03-03');
SELECT create_distributed_table('with_partitioning.partitioning_test', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$with_partitioning.partitioning_test_2010$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$with_partitioning.partitioning_test_2017$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -93,10 +93,10 @@ test: multi_subquery_in_where_reference_clause full_join adaptive_executor propa
test: multi_subquery_union multi_subquery_in_where_clause multi_subquery_misc
test: multi_agg_distinct multi_agg_approximate_distinct multi_limit_clause_approximate multi_outer_join_reference multi_single_relation_subquery multi_prepare_plsql
test: multi_reference_table multi_select_for_update relation_access_tracking
test: custom_aggregate_support aggregate_support
test: custom_aggregate_support aggregate_support tdigest_aggregate_support
test: multi_average_expression multi_working_columns multi_having_pushdown having_subquery
test: multi_array_agg multi_limit_clause multi_orderby_limit_pushdown
test: multi_jsonb_agg multi_jsonb_object_agg multi_json_agg multi_json_object_agg bool_agg ch_bench_having chbenchmark_all_queries expression_reference_join
test: multi_jsonb_agg multi_jsonb_object_agg multi_json_agg multi_json_object_agg bool_agg ch_bench_having chbenchmark_all_queries expression_reference_join anonymous_columns
test: ch_bench_subquery_repartition
test: multi_agg_type_conversion multi_count_type_conversion
test: multi_partition_pruning single_hash_repartition_join
@ -361,3 +361,8 @@ test: ensure_no_intermediate_data_leak
# in the shared memory
# --------
test: ensure_no_shared_connection_leak
# ---------
# run queries generated by sql smith that caused issues in the past
# --------
test: sqlsmith_failures

View File

@ -206,7 +206,7 @@ CREATE TABLE impressions (
SELECT create_distributed_table('companies', 'id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.companies$$)
create_distributed_table
--------------------------
@ -216,7 +216,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('campaigns', 'company_id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.campaigns$$)
create_distributed_table
--------------------------
@ -226,7 +226,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('ads', 'company_id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.ads$$)
create_distributed_table
--------------------------
@ -236,7 +236,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('clicks', 'company_id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.clicks$$)
create_distributed_table
--------------------------
@ -246,7 +246,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
SELECT create_distributed_table('impressions', 'company_id');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.impressions$$)
create_distributed_table
--------------------------

View File

@ -981,7 +981,7 @@ SELECT 1 AS a, s AS b, s AS c, s AS d, s AS e, s AS f, s AS g, s AS h FROM gener
SELECT create_distributed_table('trigger_flush','a');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is longer visible, but is still on disk.
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.trigger_flush$$)
create_distributed_table
---------------------------------------------------------------------

View File

@ -1,4 +1,5 @@
CREATE SCHEMA alter_role;
CREATE SCHEMA ",CitUs,.TeeN!?";
-- test if the passowrd of the extension owner can be upgraded
ALTER ROLE CURRENT_USER PASSWORD 'password123' VALID UNTIL 'infinity';
@ -35,11 +36,22 @@ SELECT run_command_on_workers('SHOW enable_indexonlyscan');
ALTER ROLE CURRENT_USER SET enable_hashagg TO FALSE;
SELECT run_command_on_workers('SHOW enable_hashagg');
-- provide a list of values in a supported configuration
ALTER ROLE CURRENT_USER SET search_path TO ",CitUs,.TeeN!?", alter_role, public;
-- test user defined GUCs that appear to be a list, but instead a single string
ALTER ROLE ALL SET public.myguc TO "Hello, World";
-- test for configuration values that should not be downcased even when unquoted
ALTER ROLE CURRENT_USER SET lc_messages TO 'C';
-- add worker and check all settings are copied
SELECT 1 FROM master_add_node('localhost', :worker_1_port);
SELECT run_command_on_workers('SHOW enable_hashjoin');
SELECT run_command_on_workers('SHOW enable_indexonlyscan');
SELECT run_command_on_workers('SHOW enable_hashagg');
SELECT run_command_on_workers('SHOW search_path');
SELECT run_command_on_workers('SHOW lc_messages');
SELECT run_command_on_workers('SHOW public.myguc');
-- reset to default values
ALTER ROLE CURRENT_USER RESET enable_hashagg;
@ -70,4 +82,4 @@ SELECT run_command_on_workers('SHOW enable_hashjoin');
ALTER ROLE ALL RESET enable_hashjoin;
SELECT run_command_on_workers('SHOW enable_hashjoin');
DROP SCHEMA alter_role CASCADE;
DROP SCHEMA alter_role, ",CitUs,.TeeN!?" CASCADE;

View File

@ -0,0 +1,39 @@
SET citus.next_shard_id TO 20080000;
CREATE SCHEMA anonymous_columns;
SET search_path TO anonymous_columns;
CREATE TABLE t0 (a int PRIMARY KEY, b int, "?column?" text);
SELECT create_distributed_table('t0', 'a');
INSERT INTO t0 VALUES (1, 2, 'hello'), (2, 4, 'world');
SELECT "?column?" FROM t0 ORDER BY 1;
WITH a AS (SELECT * FROM t0) SELECT "?column?" FROM a ORDER BY 1;
WITH a AS (SELECT '' FROM t0) SELECT * FROM a;
-- test CTE's that could be rewritten as subquery
WITH a AS (SELECT '' FROM t0 GROUP BY a) SELECT * FROM a;
WITH a AS (SELECT '' FROM t0 GROUP BY b) SELECT * FROM a;
WITH a AS (SELECT '','' FROM t0 GROUP BY a) SELECT * FROM a;
WITH a AS (SELECT '','' FROM t0 GROUP BY b) SELECT * FROM a;
WITH a AS (SELECT 1, * FROM t0 WHERE a = 1) SELECT * FROM a;
-- test CTE's that are referenced multiple times and hence need to stay CTE's
WITH a AS (SELECT '' FROM t0 WHERE a = 1) SELECT * FROM a, a b;
WITH a AS (SELECT '','' FROM t0 WHERE a = 42) SELECT * FROM a, a b;
-- test with explicit subqueries
SELECT * FROM (SELECT a, '' FROM t0 GROUP BY a) as foo ORDER BY 1;
SELECT * FROM (SELECT a, '', '' FROM t0 GROUP BY a ) as foo ORDER BY 1;
SELECT * FROM (SELECT b, '' FROM t0 GROUP BY b ) as foo ORDER BY 1;
SELECT * FROM (SELECT b, '', '' FROM t0 GROUP BY b ) as foo ORDER BY 1;
-- some tests that follow very similar codeoaths
SELECT a + 1 FROM t0 ORDER BY 1;
SELECT a + 1, a - 1 FROM t0 ORDER BY 1;
WITH cte1 AS (SELECT row_to_json(row(a))->'f1' FROM t0) SELECT * FROM cte1 ORDER BY 1::text;
-- clean up after test
SET client_min_messages TO WARNING;
DROP SCHEMA anonymous_columns CASCADE;

View File

@ -155,11 +155,29 @@ SELECT * FROM ref JOIN local ON (a = x);
-- in postgres we wouldn't see this modifying cte, so it is consistent with postgres.
WITH a AS (SELECT count(*) FROM test), b AS (INSERT INTO local VALUES (3,2) RETURNING *), c AS (INSERT INTO ref VALUES (3,2) RETURNING *), d AS (SELECT count(*) FROM ref JOIN local ON (a = x)) SELECT * FROM a, b, c, d ORDER BY x,y,a,b;
-- issue #3801
SET citus.shard_replication_factor TO 2;
CREATE TABLE dist_table(a int);
SELECT create_distributed_table('dist_table', 'a');
BEGIN;
-- this will use perPlacementQueryStrings, make sure it works correctly with
-- copying task
INSERT INTO dist_table SELECT a + 1 FROM dist_table;
ROLLBACK;
BEGIN;
SET citus.shard_replication_factor TO 2;
CREATE TABLE dist_table1(a int);
-- this will use queryStringList, make sure it works correctly with
-- copying task
SELECT create_distributed_table('dist_table1', 'a');
ROLLBACK;
RESET citus.enable_cte_inlining;
DELETE FROM test;
DROP TABLE test;
DROP TABLE dist_table;
DROP SCHEMA coordinator_shouldhaveshards CASCADE;

View File

@ -846,7 +846,7 @@ RESET citus.log_local_commands;
\c - - - :master_port
SET citus.next_shard_id TO 1480000;
-- local execution with custom type
-- test both local and remote execution with custom type
SET citus.replication_model TO "streaming";
SET citus.shard_replication_factor TO 1;
CREATE TYPE invite_resp AS ENUM ('yes', 'no', 'maybe');
@ -860,6 +860,105 @@ CREATE TABLE event_responses (
SELECT create_distributed_table('event_responses', 'event_id');
INSERT INTO event_responses VALUES (1, 1, 'yes'), (2, 2, 'yes'), (3, 3, 'no'), (4, 4, 'no');
CREATE OR REPLACE FUNCTION regular_func(p invite_resp)
RETURNS int AS $$
DECLARE
q1Result INT;
q2Result INT;
q3Result INT;
BEGIN
SELECT count(*) INTO q1Result FROM event_responses WHERE response = $1;
SELECT count(*) INTO q2Result FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1;
SELECT count(*) INTO q3Result FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo;
RETURN q3Result+q2Result+q1Result;
END;
$$ LANGUAGE plpgsql;
SELECT regular_func('yes');
SELECT regular_func('yes');
SELECT regular_func('yes');
SELECT regular_func('yes');
SELECT regular_func('yes');
SELECT regular_func('yes');
SELECT regular_func('yes');
SELECT regular_func('yes');
CREATE OR REPLACE PROCEDURE regular_procedure(p invite_resp)
AS $$
BEGIN
PERFORM * FROM event_responses WHERE response = $1;
PERFORM * FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1;
PERFORM * FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo;
END;
$$ LANGUAGE plpgsql;
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
CALL regular_procedure('no');
PREPARE multi_shard_no_dist_key(invite_resp) AS select * from event_responses where response = $1::invite_resp LIMIT 1;
EXECUTE multi_shard_no_dist_key('yes');
EXECUTE multi_shard_no_dist_key('yes');
EXECUTE multi_shard_no_dist_key('yes');
EXECUTE multi_shard_no_dist_key('yes');
EXECUTE multi_shard_no_dist_key('yes');
EXECUTE multi_shard_no_dist_key('yes');
EXECUTE multi_shard_no_dist_key('yes');
PREPARE multi_shard_with_dist_key(int, invite_resp) AS select * from event_responses where event_id > $1 AND response = $2::invite_resp LIMIT 1;
EXECUTE multi_shard_with_dist_key(1, 'yes');
EXECUTE multi_shard_with_dist_key(1, 'yes');
EXECUTE multi_shard_with_dist_key(1, 'yes');
EXECUTE multi_shard_with_dist_key(1, 'yes');
EXECUTE multi_shard_with_dist_key(1, 'yes');
EXECUTE multi_shard_with_dist_key(1, 'yes');
EXECUTE multi_shard_with_dist_key(1, 'yes');
PREPARE query_pushdown_no_dist_key(invite_resp) AS select * from event_responses e1 LEFT JOIN event_responses e2 USING(event_id) where e1.response = $1::invite_resp LIMIT 1;
EXECUTE query_pushdown_no_dist_key('yes');
EXECUTE query_pushdown_no_dist_key('yes');
EXECUTE query_pushdown_no_dist_key('yes');
EXECUTE query_pushdown_no_dist_key('yes');
EXECUTE query_pushdown_no_dist_key('yes');
EXECUTE query_pushdown_no_dist_key('yes');
EXECUTE query_pushdown_no_dist_key('yes');
PREPARE insert_select_via_coord(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp LIMIT 1 ON CONFLICT (event_id, user_id) DO NOTHING ;
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
EXECUTE insert_select_via_coord('yes');
PREPARE insert_select_pushdown(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp ON CONFLICT (event_id, user_id) DO NOTHING;
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
EXECUTE insert_select_pushdown('yes');
PREPARE router_select_with_no_dist_key_filter(invite_resp) AS select * from event_responses where event_id = 1 AND response = $1::invite_resp LIMIT 1;
EXECUTE router_select_with_no_dist_key_filter('yes');
EXECUTE router_select_with_no_dist_key_filter('yes');
EXECUTE router_select_with_no_dist_key_filter('yes');
EXECUTE router_select_with_no_dist_key_filter('yes');
EXECUTE router_select_with_no_dist_key_filter('yes');
EXECUTE router_select_with_no_dist_key_filter('yes');
EXECUTE router_select_with_no_dist_key_filter('yes');
-- rest of the tests assume the table is empty
TRUNCATE event_responses;
CREATE OR REPLACE PROCEDURE register_for_event(p_event_id int, p_user_id int, p_choice invite_resp)
LANGUAGE plpgsql AS $fn$
BEGIN

Some files were not shown because too many files have changed in this diff Show More