Compare commits

...

11 Commits

Author SHA1 Message Date
Onur Tirtir 8e5b9a06ad Add changelog for 10.2.1
(cherry picked from commit 2f1bf9499f)

 Conflicts:
	CHANGELOG.md
2021-09-24 13:11:30 +03:00
Onur Tirtir aed6776d1f Bump citus version to 10.2.1 2021-09-24 12:53:51 +03:00
SaitTalhaNisanci a9dced4291 Update images to use rc (#5320)
(cherry picked from commit 800ad5eca6)
2021-09-24 11:42:53 +03:00
Jeff Davis 34744501ce Columnar: only call BuildStripeMetadata() with heap tuple.
BuildStripeMetadata() calls HeapTupleHeaderGetXmin(), which must only
be called on a proper heap tuple with MVCC information. Make sure the
caller passes the heap tuple, and not a datum tuple.

Fixes #5318.

(cherry picked from commit d49d321eac)
2021-09-24 10:57:22 +03:00
tejeswarm 86b57f426b Parition shards to be colocated with the parent shards 2021-09-23 11:51:03 -07:00
Onur Tirtir 9801f743ce Revoke read access to columnar.chunk from unprivileged user (#5313)
Since this could expose chunk min/max values to unprivileged users.
(cherry picked from commit 77a2dd68da)
2021-09-22 16:24:08 +03:00
Onur Tirtir 8e3246a2f3 Columnar CustomScan: Pushdown BoolExpr's as we do before
(cherry picked from commit 68335285b4)
2021-09-22 11:44:12 +03:00
Onur Tirtir 1feb7102b8 Check if xact id is in progress before checking if aborted (#5312)
(cherry picked from commit e6ed764f63)
2021-09-22 11:44:12 +03:00
Onur Tirtir 9cde3d4122 Add CheckCitusVersion() calls to columnarAM (#5308)
Considering all code-paths that we might interact with a columnar table,
add `CheckCitusVersion` calls to tableAM callbacks:
- initializing table scan (`columnar_beginscan` & `columnar_index_fetch_begin`)
- setting a new filenode for a relation (storage initializiation or a table rewrite)
- truncating the storage
- inserting tuple (single and multi)

Also add `CheckCitusVersion` call to:
- drop hook (`ColumnarTableDropHook`)
- `alter_columnar_table_set` & `alter_columnar_table_reset` UDFs
(cherry picked from commit f8b1ff7214)
2021-09-20 17:33:51 +03:00
Onder Kalaci 7da6d68675 Add missing version checks for citus_internal_XXX functions
(cherry picked from commit cea937f52f)
2021-09-20 13:50:47 +03:00
Hanefi Onaldi a913b90ff3
Bump Citus version to 10.2.0 2021-09-15 05:55:36 +03:00
24 changed files with 1062 additions and 82 deletions

View File

@ -451,7 +451,7 @@ workflows:
- build: - build:
name: build-14 name: build-14
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
- check-style - check-style
- check-sql-snapshots - check-sql-snapshots
@ -607,74 +607,74 @@ workflows:
- test-citus: - test-citus:
name: 'test-14_check-multi' name: 'test-14_check-multi'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-multi make: check-multi
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-multi-1' name: 'test-14_check-multi-1'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-multi-1 make: check-multi-1
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-mx' name: 'test-14_check-mx'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-multi-mx make: check-multi-mx
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-vanilla' name: 'test-14_check-vanilla'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-vanilla make: check-vanilla
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-isolation' name: 'test-14_check-isolation'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-isolation make: check-isolation
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-worker' name: 'test-14_check-worker'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-worker make: check-worker
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-operations' name: 'test-14_check-operations'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-operations make: check-operations
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-follower-cluster' name: 'test-14_check-follower-cluster'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-follower-cluster make: check-follower-cluster
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-columnar' name: 'test-14_check-columnar'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-columnar make: check-columnar
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-columnar-isolation' name: 'test-14_check-columnar-isolation'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
make: check-columnar-isolation make: check-columnar-isolation
requires: [build-14] requires: [build-14]
- tap-test-citus: - tap-test-citus:
name: 'test_14_tap-recovery' name: 'test_14_tap-recovery'
pg_major: 14 pg_major: 14
image_tag: '14beta3' image_tag: '14rc1'
suite: recovery suite: recovery
requires: [build-14] requires: [build-14]
- test-citus: - test-citus:
name: 'test-14_check-failure' name: 'test-14_check-failure'
pg_major: 14 pg_major: 14
image: citus/failtester image: citus/failtester
image_tag: '14beta3' image_tag: '14rc1'
make: check-failure make: check-failure
requires: [build-14] requires: [build-14]
@ -689,14 +689,14 @@ workflows:
name: 'test-12-14_check-pg-upgrade' name: 'test-12-14_check-pg-upgrade'
old_pg_major: 12 old_pg_major: 12
new_pg_major: 14 new_pg_major: 14
image_tag: '12-13-14' image_tag: '12.8-13.4-14rc1'
requires: [build-12,build-14] requires: [build-12,build-14]
- test-pg-upgrade: - test-pg-upgrade:
name: 'test-13-14_check-pg-upgrade' name: 'test-13-14_check-pg-upgrade'
old_pg_major: 13 old_pg_major: 13
new_pg_major: 14 new_pg_major: 14
image_tag: '12-13-14' image_tag: '12.8-13.4-14rc1'
requires: [build-13,build-14] requires: [build-13,build-14]
- test-citus-upgrade: - test-citus-upgrade:

View File

@ -1,3 +1,22 @@
### citus v10.2.1 (September 24, 2021) ###
* Adds missing version-mismatch checks for columnar tables
* Adds missing version-mismatch checks for internal functions
* Fixes a bug that could cause partition shards being not co-located with
parent shards
* Fixes a bug that prevents pushing down boolean expressions when using
columnar custom scan
* Fixes a clog lookup failure that could occur when writing to a columnar table
* Fixes an issue that could cause unexpected errors when there is an
in-progress write to a columnar table
* Revokes read access to `columnar.chunk` from unprivileged user
### citus v10.2.0 (September 14, 2021) ### ### citus v10.2.0 (September 14, 2021) ###
* Adds PostgreSQL 14 support * Adds PostgreSQL 14 support

18
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for Citus 10.2devel. # Generated by GNU Autoconf 2.69 for Citus 10.2.1.
# #
# #
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -579,8 +579,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='Citus' PACKAGE_NAME='Citus'
PACKAGE_TARNAME='citus' PACKAGE_TARNAME='citus'
PACKAGE_VERSION='10.2devel' PACKAGE_VERSION='10.2.1'
PACKAGE_STRING='Citus 10.2devel' PACKAGE_STRING='Citus 10.2.1'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
PACKAGE_URL='' PACKAGE_URL=''
@ -1260,7 +1260,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures Citus 10.2devel to adapt to many kinds of systems. \`configure' configures Citus 10.2.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1322,7 +1322,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of Citus 10.2devel:";; short | recursive ) echo "Configuration of Citus 10.2.1:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1425,7 +1425,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
Citus configure 10.2devel Citus configure 10.2.1
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -1908,7 +1908,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by Citus $as_me 10.2devel, which was It was created by Citus $as_me 10.2.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -5356,7 +5356,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by Citus $as_me 10.2devel, which was This file was extended by Citus $as_me 10.2.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -5418,7 +5418,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
Citus config.status 10.2devel Citus config.status 10.2.1
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

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

View File

@ -605,10 +605,11 @@ RelationIdGetNumberOfAttributes(Oid relationId)
/* /*
* CheckVarStats() checks whether a qual involving this Var is likely to be * CheckVarStats() checks whether a qual involving this Var is likely to be
* useful based on the correlation stats. If so, or if stats are unavailable, * useful based on the correlation stats. If so, or if stats are unavailable,
* return true; otherwise return false. * return true; otherwise return false and sets absVarCorrelation in case
* caller wants to use for logging purposes.
*/ */
static bool static bool
CheckVarStats(PlannerInfo *root, Var *var, Oid sortop) CheckVarStats(PlannerInfo *root, Var *var, Oid sortop, float4 *absVarCorrelation)
{ {
/* /*
* Collect isunique, ndistinct, and varCorrelation. * Collect isunique, ndistinct, and varCorrelation.
@ -642,6 +643,14 @@ CheckVarStats(PlannerInfo *root, Var *var, Oid sortop)
*/ */
if (Abs(varCorrelation) < ColumnarQualPushdownCorrelationThreshold) if (Abs(varCorrelation) < ColumnarQualPushdownCorrelationThreshold)
{ {
if (absVarCorrelation)
{
/*
* Report absVarCorrelation if caller wants to know why given
* var is rejected.
*/
*absVarCorrelation = Abs(varCorrelation);
}
return false; return false;
} }
@ -674,7 +683,7 @@ ExprReferencesRelid(Expr *expr, Index relid)
/* /*
* CheckPushdownClause tests to see if clause is a candidate for pushing down * ExtractPushdownClause extracts an Expr node from given clause for pushing down
* into the given rel (including join clauses). This test may not be exact in * into the given rel (including join clauses). This test may not be exact in
* all cases; it's used to reduce the search space for parameterization. * all cases; it's used to reduce the search space for parameterization.
* *
@ -683,19 +692,134 @@ ExprReferencesRelid(Expr *expr, Index relid)
* and that doesn't seem worth the effort. Here we just look for "Var op Expr" * and that doesn't seem worth the effort. Here we just look for "Var op Expr"
* or "Expr op Var", where Var references rel and Expr references other rels * or "Expr op Var", where Var references rel and Expr references other rels
* (or no rels at all). * (or no rels at all).
*
* Moreover, this function also looks into BoolExpr's to recursively extract
* pushdownable OpExpr's of them:
* i) AND_EXPR:
* Take pushdownable args of AND expressions by ignoring the other args.
* ii) OR_EXPR:
* Ignore the whole OR expression if we cannot exract a pushdownable Expr
* from one of its args.
* iii) NOT_EXPR:
* Simply ignore NOT expressions since we don't expect to see them before
* an expression that we can pushdown, see the comment in function.
*
* The reasoning for those three rules could also be summarized as such;
* for any expression that we cannot push-down, we must assume that it
* evaluates to true.
*
* For example, given following WHERE clause:
* (
* (a > random() OR a < 30)
* AND
* a < 200
* ) OR
* (
* a = 300
* OR
* a > 400
* );
* Even if we can pushdown (a < 30), we cannot pushdown (a > random() OR a < 30)
* due to (a > random()). However, we can pushdown (a < 200), so we extract
* (a < 200) from the lhs of the top level OR expression.
*
* For the rhs of the top level OR expression, since we can pushdown both (a = 300)
* and (a > 400), we take this part as is.
*
* Finally, since both sides of the top level OR expression yielded pushdownable
* expressions, we will pushdown the following:
* (a < 200) OR ((a = 300) OR (a > 400))
*/ */
static bool static Expr *
CheckPushdownClause(PlannerInfo *root, RelOptInfo *rel, Expr *clause) ExtractPushdownClause(PlannerInfo *root, RelOptInfo *rel, Node *node)
{ {
if (!IsA(clause, OpExpr) || list_length(((OpExpr *) clause)->args) != 2) CHECK_FOR_INTERRUPTS();
check_stack_depth();
if (node == NULL)
{
return NULL;
}
if (IsA(node, BoolExpr))
{
BoolExpr *boolExpr = castNode(BoolExpr, node);
if (boolExpr->boolop == NOT_EXPR)
{
/*
* Standard planner should have already applied de-morgan rule to
* simple NOT expressions. If we encounter with such an expression
* here, then it can't be a pushdownable one, such as:
* WHERE id NOT IN (SELECT id FROM something).
*/
ereport(ColumnarPlannerDebugLevel,
(errmsg("columnar planner: cannot push down clause: "
"must not contain a subplan")));
return NULL;
}
List *pushdownableArgs = NIL;
Node *boolExprArg = NULL;
foreach_ptr(boolExprArg, boolExpr->args)
{
Expr *pushdownableArg = ExtractPushdownClause(root, rel,
(Node *) boolExprArg);
if (pushdownableArg)
{
pushdownableArgs = lappend(pushdownableArgs, pushdownableArg);
}
else if (boolExpr->boolop == OR_EXPR)
{
ereport(ColumnarPlannerDebugLevel,
(errmsg("columnar planner: cannot push down clause: "
"all arguments of an OR expression must be "
"pushdownable but one of them was not, due "
"to the reason given above")));
return NULL;
}
/* simply skip AND args that we cannot pushdown */
}
int npushdownableArgs = list_length(pushdownableArgs);
if (npushdownableArgs == 0)
{
ereport(ColumnarPlannerDebugLevel,
(errmsg("columnar planner: cannot push down clause: "
"none of the arguments were pushdownable, "
"due to the reason(s) given above ")));
return NULL;
}
else if (npushdownableArgs == 1)
{
return (Expr *) linitial(pushdownableArgs);
}
if (boolExpr->boolop == AND_EXPR)
{
return make_andclause(pushdownableArgs);
}
else if (boolExpr->boolop == OR_EXPR)
{
return make_orclause(pushdownableArgs);
}
else
{
/* already discarded NOT expr, so should not be reachable */
return NULL;
}
}
if (!IsA(node, OpExpr) || list_length(((OpExpr *) node)->args) != 2)
{ {
ereport(ColumnarPlannerDebugLevel, ereport(ColumnarPlannerDebugLevel,
(errmsg("columnar planner: cannot push down clause: " (errmsg("columnar planner: cannot push down clause: "
"must be binary operator expression"))); "must be binary operator expression")));
return false; return NULL;
} }
OpExpr *opExpr = castNode(OpExpr, clause); OpExpr *opExpr = castNode(OpExpr, node);
Expr *lhs = list_nth(opExpr->args, 0); Expr *lhs = list_nth(opExpr->args, 0);
Expr *rhs = list_nth(opExpr->args, 1); Expr *rhs = list_nth(opExpr->args, 1);
@ -721,15 +845,15 @@ CheckPushdownClause(PlannerInfo *root, RelOptInfo *rel, Expr *clause)
"must match 'Var <op> Expr' or 'Expr <op> Var'"), "must match 'Var <op> Expr' or 'Expr <op> Var'"),
errhint("Var must only reference this rel, " errhint("Var must only reference this rel, "
"and Expr must not reference this rel"))); "and Expr must not reference this rel")));
return false; return NULL;
} }
if (varSide->varattno <= 0) if (varSide->varattno <= 0)
{ {
ereport(ColumnarPlannerDebugLevel, ereport(ColumnarPlannerDebugLevel,
(errmsg("columnar planner: cannot push down clause: " (errmsg("columnar planner: cannot push down clause: "
"var is whole-row reference"))); "var is whole-row reference or system column")));
return false; return NULL;
} }
if (contain_volatile_functions((Node *) exprSide)) if (contain_volatile_functions((Node *) exprSide))
@ -737,7 +861,7 @@ CheckPushdownClause(PlannerInfo *root, RelOptInfo *rel, Expr *clause)
ereport(ColumnarPlannerDebugLevel, ereport(ColumnarPlannerDebugLevel,
(errmsg("columnar planner: cannot push down clause: " (errmsg("columnar planner: cannot push down clause: "
"expr contains volatile functions"))); "expr contains volatile functions")));
return false; return NULL;
} }
/* only the default opclass is used for qual pushdown. */ /* only the default opclass is used for qual pushdown. */
@ -753,7 +877,7 @@ CheckPushdownClause(PlannerInfo *root, RelOptInfo *rel, Expr *clause)
(errmsg("columnar planner: cannot push down clause: " (errmsg("columnar planner: cannot push down clause: "
"cannot find default btree opclass and opfamily for type: %s", "cannot find default btree opclass and opfamily for type: %s",
format_type_be(varSide->vartype)))); format_type_be(varSide->vartype))));
return false; return NULL;
} }
if (!op_in_opfamily(opExpr->opno, varOpFamily)) if (!op_in_opfamily(opExpr->opno, varOpFamily))
@ -762,7 +886,7 @@ CheckPushdownClause(PlannerInfo *root, RelOptInfo *rel, Expr *clause)
(errmsg("columnar planner: cannot push down clause: " (errmsg("columnar planner: cannot push down clause: "
"operator %d not a member of opfamily %d", "operator %d not a member of opfamily %d",
opExpr->opno, varOpFamily))); opExpr->opno, varOpFamily)));
return false; return NULL;
} }
Oid sortop = get_opfamily_member(varOpFamily, varOpcInType, Oid sortop = get_opfamily_member(varOpFamily, varOpcInType,
@ -773,15 +897,20 @@ CheckPushdownClause(PlannerInfo *root, RelOptInfo *rel, Expr *clause)
* Check that statistics on the Var support the utility of this * Check that statistics on the Var support the utility of this
* clause. * clause.
*/ */
if (!CheckVarStats(root, varSide, sortop)) float4 absVarCorrelation = 0;
if (!CheckVarStats(root, varSide, sortop, &absVarCorrelation))
{ {
ereport(ColumnarPlannerDebugLevel, ereport(ColumnarPlannerDebugLevel,
(errmsg("columnar planner: cannot push down clause: " (errmsg("columnar planner: cannot push down clause: "
"var attribute %d is uncorrelated", varSide->varattno))); "absolute correlation (%.3f) of var attribute %d is "
return false; "smaller than the value configured in "
"\"columnar.qual_pushdown_correlation_threshold\" "
"(%.3f)", absVarCorrelation, varSide->varattno,
ColumnarQualPushdownCorrelationThreshold)));
return NULL;
} }
return true; return (Expr *) node;
} }
@ -806,12 +935,19 @@ FilterPushdownClauses(PlannerInfo *root, RelOptInfo *rel, List *inputClauses)
* there's something we should do with pseudoconstants here. * there's something we should do with pseudoconstants here.
*/ */
if (rinfo->pseudoconstant || if (rinfo->pseudoconstant ||
!bms_is_member(rel->relid, rinfo->required_relids) || !bms_is_member(rel->relid, rinfo->required_relids))
!CheckPushdownClause(root, rel, rinfo->clause))
{ {
continue; continue;
} }
Expr *pushdownableExpr = ExtractPushdownClause(root, rel, (Node *) rinfo->clause);
if (!pushdownableExpr)
{
continue;
}
rinfo = copyObject(rinfo);
rinfo->clause = pushdownableExpr;
filteredClauses = lappend(filteredClauses, rinfo); filteredClauses = lappend(filteredClauses, rinfo);
} }

View File

@ -1178,8 +1178,18 @@ UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, bool *update,
heap_inplace_update(columnarStripes, modifiedTuple); heap_inplace_update(columnarStripes, modifiedTuple);
/*
* Existing tuple now contains modifications, because we used
* heap_inplace_update().
*/
HeapTuple newTuple = oldTuple;
/*
* Must not pass modifiedTuple, because BuildStripeMetadata expects a real
* heap tuple with MVCC fields.
*/
StripeMetadata *modifiedStripeMetadata = BuildStripeMetadata(columnarStripes, StripeMetadata *modifiedStripeMetadata = BuildStripeMetadata(columnarStripes,
modifiedTuple); newTuple);
CommandCounterIncrement(); CommandCounterIncrement();
@ -1233,6 +1243,8 @@ ReadDataFileStripeList(uint64 storageId, Snapshot snapshot)
/* /*
* BuildStripeMetadata builds a StripeMetadata object from given heap tuple. * BuildStripeMetadata builds a StripeMetadata object from given heap tuple.
*
* NB: heapTuple must be a proper heap tuple with MVCC fields.
*/ */
static StripeMetadata * static StripeMetadata *
BuildStripeMetadata(Relation columnarStripes, HeapTuple heapTuple) BuildStripeMetadata(Relation columnarStripes, HeapTuple heapTuple)
@ -1269,7 +1281,8 @@ BuildStripeMetadata(Relation columnarStripes, HeapTuple heapTuple)
* subtransaction id here. * subtransaction id here.
*/ */
TransactionId entryXmin = HeapTupleHeaderGetXmin(heapTuple->t_data); TransactionId entryXmin = HeapTupleHeaderGetXmin(heapTuple->t_data);
stripeMetadata->aborted = TransactionIdDidAbort(entryXmin); stripeMetadata->aborted = !TransactionIdIsInProgress(entryXmin) &&
TransactionIdDidAbort(entryXmin);
stripeMetadata->insertedByCurrentXact = stripeMetadata->insertedByCurrentXact =
TransactionIdIsCurrentTransactionId(entryXmin); TransactionIdIsCurrentTransactionId(entryXmin);

View File

@ -173,6 +173,8 @@ columnar_beginscan(Relation relation, Snapshot snapshot,
ParallelTableScanDesc parallel_scan, ParallelTableScanDesc parallel_scan,
uint32 flags) uint32 flags)
{ {
CheckCitusVersion(ERROR);
int natts = relation->rd_att->natts; int natts = relation->rd_att->natts;
/* attr_needed represents 0-indexed attribute numbers */ /* attr_needed represents 0-indexed attribute numbers */
@ -418,6 +420,8 @@ columnar_parallelscan_reinitialize(Relation rel, ParallelTableScanDesc pscan)
static IndexFetchTableData * static IndexFetchTableData *
columnar_index_fetch_begin(Relation rel) columnar_index_fetch_begin(Relation rel)
{ {
CheckCitusVersion(ERROR);
Oid relfilenode = rel->rd_node.relNode; Oid relfilenode = rel->rd_node.relNode;
if (PendingWritesInUpperTransactions(relfilenode, GetCurrentSubTransactionId())) if (PendingWritesInUpperTransactions(relfilenode, GetCurrentSubTransactionId()))
{ {
@ -638,6 +642,8 @@ static bool
columnar_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, columnar_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot,
Snapshot snapshot) Snapshot snapshot)
{ {
CheckCitusVersion(ERROR);
uint64 rowNumber = tid_to_row_number(slot->tts_tid); uint64 rowNumber = tid_to_row_number(slot->tts_tid);
StripeMetadata *stripeMetadata = FindStripeByRowNumber(rel, rowNumber, snapshot); StripeMetadata *stripeMetadata = FindStripeByRowNumber(rel, rowNumber, snapshot);
return stripeMetadata != NULL; return stripeMetadata != NULL;
@ -670,6 +676,8 @@ static void
columnar_tuple_insert(Relation relation, TupleTableSlot *slot, CommandId cid, columnar_tuple_insert(Relation relation, TupleTableSlot *slot, CommandId cid,
int options, BulkInsertState bistate) int options, BulkInsertState bistate)
{ {
CheckCitusVersion(ERROR);
/* /*
* columnar_init_write_state allocates the write state in a longer * columnar_init_write_state allocates the write state in a longer
* lasting context, so no need to worry about it. * lasting context, so no need to worry about it.
@ -716,6 +724,8 @@ static void
columnar_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, columnar_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
CommandId cid, int options, BulkInsertState bistate) CommandId cid, int options, BulkInsertState bistate)
{ {
CheckCitusVersion(ERROR);
ColumnarWriteState *writeState = columnar_init_write_state(relation, ColumnarWriteState *writeState = columnar_init_write_state(relation,
RelationGetDescr(relation), RelationGetDescr(relation),
GetCurrentSubTransactionId()); GetCurrentSubTransactionId());
@ -790,6 +800,8 @@ columnar_relation_set_new_filenode(Relation rel,
TransactionId *freezeXid, TransactionId *freezeXid,
MultiXactId *minmulti) MultiXactId *minmulti)
{ {
CheckCitusVersion(ERROR);
if (persistence == RELPERSISTENCE_UNLOGGED) if (persistence == RELPERSISTENCE_UNLOGGED)
{ {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@ -825,6 +837,8 @@ columnar_relation_set_new_filenode(Relation rel,
static void static void
columnar_relation_nontransactional_truncate(Relation rel) columnar_relation_nontransactional_truncate(Relation rel)
{ {
CheckCitusVersion(ERROR);
RelFileNode relfilenode = rel->rd_node; RelFileNode relfilenode = rel->rd_node;
NonTransactionDropWriteState(relfilenode.relNode); NonTransactionDropWriteState(relfilenode.relNode);
@ -871,6 +885,8 @@ columnar_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
double *tups_vacuumed, double *tups_vacuumed,
double *tups_recently_dead) double *tups_recently_dead)
{ {
CheckCitusVersion(ERROR);
TupleDesc sourceDesc = RelationGetDescr(OldHeap); TupleDesc sourceDesc = RelationGetDescr(OldHeap);
TupleDesc targetDesc = RelationGetDescr(NewHeap); TupleDesc targetDesc = RelationGetDescr(NewHeap);
@ -967,6 +983,15 @@ static void
columnar_vacuum_rel(Relation rel, VacuumParams *params, columnar_vacuum_rel(Relation rel, VacuumParams *params,
BufferAccessStrategy bstrategy) BufferAccessStrategy bstrategy)
{ {
if (!CheckCitusVersion(WARNING))
{
/*
* Skip if the extension catalogs are not up-to-date, but avoid
* erroring during auto-vacuum.
*/
return;
}
/* /*
* If metapage version of relation is older, then we hint users to VACUUM * If metapage version of relation is older, then we hint users to VACUUM
* the relation in ColumnarMetapageCheckVersion. So if needed, upgrade * the relation in ColumnarMetapageCheckVersion. So if needed, upgrade
@ -1276,6 +1301,8 @@ columnar_index_build_range_scan(Relation columnarRelation,
void *callback_state, void *callback_state,
TableScanDesc scan) TableScanDesc scan)
{ {
CheckCitusVersion(ERROR);
if (start_blockno != 0 || numblocks != InvalidBlockNumber) if (start_blockno != 0 || numblocks != InvalidBlockNumber)
{ {
/* /*
@ -1524,6 +1551,8 @@ columnar_index_validate_scan(Relation columnarRelation,
ValidateIndexState * ValidateIndexState *
validateIndexState) validateIndexState)
{ {
CheckCitusVersion(ERROR);
ColumnarReportTotalVirtualBlocks(columnarRelation, snapshot, ColumnarReportTotalVirtualBlocks(columnarRelation, snapshot,
PROGRESS_SCAN_BLOCKS_TOTAL); PROGRESS_SCAN_BLOCKS_TOTAL);
@ -1694,6 +1723,8 @@ TupleSortSkipSmallerItemPointers(Tuplesortstate *tupleSort, ItemPointer targetIt
static uint64 static uint64
columnar_relation_size(Relation rel, ForkNumber forkNumber) columnar_relation_size(Relation rel, ForkNumber forkNumber)
{ {
CheckCitusVersion(ERROR);
uint64 nblocks = 0; uint64 nblocks = 0;
/* Open it at the smgr level if not already done */ /* Open it at the smgr level if not already done */
@ -1719,6 +1750,8 @@ columnar_relation_size(Relation rel, ForkNumber forkNumber)
static bool static bool
columnar_relation_needs_toast_table(Relation rel) columnar_relation_needs_toast_table(Relation rel)
{ {
CheckCitusVersion(ERROR);
return false; return false;
} }
@ -1728,6 +1761,8 @@ columnar_estimate_rel_size(Relation rel, int32 *attr_widths,
BlockNumber *pages, double *tuples, BlockNumber *pages, double *tuples,
double *allvisfrac) double *allvisfrac)
{ {
CheckCitusVersion(ERROR);
RelationOpenSmgr(rel); RelationOpenSmgr(rel);
*pages = smgrnblocks(rel->rd_smgr, MAIN_FORKNUM); *pages = smgrnblocks(rel->rd_smgr, MAIN_FORKNUM);
*tuples = ColumnarTableRowCount(rel); *tuples = ColumnarTableRowCount(rel);
@ -1899,6 +1934,8 @@ ColumnarTableDropHook(Oid relid)
if (IsColumnarTableAmTable(relid)) if (IsColumnarTableAmTable(relid))
{ {
CheckCitusVersion(ERROR);
/* /*
* Drop metadata. No need to drop storage here since for * Drop metadata. No need to drop storage here since for
* tableam tables storage is managed by postgres. * tableam tables storage is managed by postgres.
@ -2020,6 +2057,8 @@ ColumnarProcessUtility(PlannedStmt *pstmt,
GetCreateIndexRelationLockMode(indexStmt)); GetCreateIndexRelationLockMode(indexStmt));
if (rel->rd_tableam == GetColumnarTableAmRoutine()) if (rel->rd_tableam == GetColumnarTableAmRoutine())
{ {
CheckCitusVersion(ERROR);
if (!ColumnarSupportsIndexAM(indexStmt->accessMethod)) if (!ColumnarSupportsIndexAM(indexStmt->accessMethod))
{ {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@ -2356,6 +2395,8 @@ PG_FUNCTION_INFO_V1(alter_columnar_table_set);
Datum Datum
alter_columnar_table_set(PG_FUNCTION_ARGS) alter_columnar_table_set(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
Oid relationId = PG_GETARG_OID(0); Oid relationId = PG_GETARG_OID(0);
Relation rel = table_open(relationId, AccessExclusiveLock); /* ALTER TABLE LOCK */ Relation rel = table_open(relationId, AccessExclusiveLock); /* ALTER TABLE LOCK */
@ -2483,6 +2524,8 @@ PG_FUNCTION_INFO_V1(alter_columnar_table_reset);
Datum Datum
alter_columnar_table_reset(PG_FUNCTION_ARGS) alter_columnar_table_reset(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
Oid relationId = PG_GETARG_OID(0); Oid relationId = PG_GETARG_OID(0);
Relation rel = table_open(relationId, AccessExclusiveLock); /* ALTER TABLE LOCK */ Relation rel = table_open(relationId, AccessExclusiveLock); /* ALTER TABLE LOCK */

View File

@ -0,0 +1,5 @@
-- columnar--10.2-1--10.2-2.sql
-- revoke read access for columnar.chunk from unprivileged
-- user as it contains chunk min/max values
REVOKE SELECT ON columnar.chunk FROM PUBLIC;

View File

@ -0,0 +1,4 @@
-- columnar--10.2-2--10.2-1.sql
-- grant read access for columnar.chunk to unprivileged user
GRANT SELECT ON columnar.chunk TO PUBLIC;

View File

@ -1,6 +1,6 @@
# Citus extension # Citus extension
comment = 'Citus distributed database' comment = 'Citus distributed database'
default_version = '10.2-1' default_version = '10.2-2'
module_pathname = '$libdir/citus' module_pathname = '$libdir/citus'
relocatable = false relocatable = false
schema = pg_catalog schema = pg_catalog

View File

@ -554,11 +554,16 @@ CreateDistributedTable(Oid relationId, Var *distributionColumn, char distributio
{ {
List *partitionList = PartitionList(relationId); List *partitionList = PartitionList(relationId);
Oid partitionRelationId = InvalidOid; Oid partitionRelationId = InvalidOid;
Oid namespaceId = get_rel_namespace(relationId);
char *schemaName = get_namespace_name(namespaceId);
char *relationName = get_rel_name(relationId);
char *parentRelationName = quote_qualified_identifier(schemaName, relationName);
foreach_oid(partitionRelationId, partitionList) foreach_oid(partitionRelationId, partitionList)
{ {
CreateDistributedTable(partitionRelationId, distributionColumn, CreateDistributedTable(partitionRelationId, distributionColumn,
distributionMethod, shardCount, false, distributionMethod, shardCount, false,
colocateWithTableName, viaDeprecatedAPI); parentRelationName, viaDeprecatedAPI);
} }
} }

View File

@ -2061,6 +2061,8 @@ ShouldInitiateMetadataSync(bool *lockFailure)
Datum Datum
citus_internal_add_partition_metadata(PG_FUNCTION_ARGS) citus_internal_add_partition_metadata(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
PG_ENSURE_ARGNOTNULL(0, "relation"); PG_ENSURE_ARGNOTNULL(0, "relation");
Oid relationId = PG_GETARG_OID(0); Oid relationId = PG_GETARG_OID(0);
@ -2211,6 +2213,8 @@ EnsurePartitionMetadataIsSane(Oid relationId, char distributionMethod, int coloc
Datum Datum
citus_internal_add_shard_metadata(PG_FUNCTION_ARGS) citus_internal_add_shard_metadata(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
PG_ENSURE_ARGNOTNULL(0, "relation"); PG_ENSURE_ARGNOTNULL(0, "relation");
Oid relationId = PG_GETARG_OID(0); Oid relationId = PG_GETARG_OID(0);
@ -2426,6 +2430,8 @@ EnsureShardMetadataIsSane(Oid relationId, int64 shardId, char storageType,
Datum Datum
citus_internal_add_placement_metadata(PG_FUNCTION_ARGS) citus_internal_add_placement_metadata(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
int64 shardId = PG_GETARG_INT64(0); int64 shardId = PG_GETARG_INT64(0);
int32 shardState = PG_GETARG_INT32(1); int32 shardState = PG_GETARG_INT32(1);
int64 shardLength = PG_GETARG_INT64(2); int64 shardLength = PG_GETARG_INT64(2);
@ -2537,6 +2543,8 @@ ShouldSkipMetadataChecks(void)
Datum Datum
citus_internal_update_placement_metadata(PG_FUNCTION_ARGS) citus_internal_update_placement_metadata(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
int64 shardId = PG_GETARG_INT64(0); int64 shardId = PG_GETARG_INT64(0);
int32 sourceGroupId = PG_GETARG_INT32(1); int32 sourceGroupId = PG_GETARG_INT32(1);
int32 targetGroupId = PG_GETARG_INT32(2); int32 targetGroupId = PG_GETARG_INT32(2);
@ -2602,6 +2610,8 @@ citus_internal_update_placement_metadata(PG_FUNCTION_ARGS)
Datum Datum
citus_internal_delete_shard_metadata(PG_FUNCTION_ARGS) citus_internal_delete_shard_metadata(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
int64 shardId = PG_GETARG_INT64(0); int64 shardId = PG_GETARG_INT64(0);
if (!ShouldSkipMetadataChecks()) if (!ShouldSkipMetadataChecks())
@ -2640,6 +2650,8 @@ citus_internal_delete_shard_metadata(PG_FUNCTION_ARGS)
Datum Datum
citus_internal_update_relation_colocation(PG_FUNCTION_ARGS) citus_internal_update_relation_colocation(PG_FUNCTION_ARGS)
{ {
CheckCitusVersion(ERROR);
Oid relationId = PG_GETARG_OID(0); Oid relationId = PG_GETARG_OID(0);
uint32 tagetColocationId = PG_GETARG_UINT32(1); uint32 tagetColocationId = PG_GETARG_UINT32(1);

View File

@ -0,0 +1,5 @@
-- citus--10.2-1--10.2-2
-- bump version to 10.2-2
#include "../../columnar/sql/columnar--10.2-1--10.2-2.sql"

View File

@ -0,0 +1,3 @@
-- citus--10.2-2--10.2-1
#include "../../../columnar/sql/downgrades/columnar--10.2-2--10.2-1.sql"

View File

@ -246,3 +246,6 @@ s/TRIM\(BOTH FROM value\)/btrim\(value\)/g
s/pg14\.idx.*/pg14\.xxxxx/g s/pg14\.idx.*/pg14\.xxxxx/g
s/CREATE TABLESPACE test_tablespace LOCATION.*/CREATE TABLESPACE test_tablespace LOCATION XXXX/g s/CREATE TABLESPACE test_tablespace LOCATION.*/CREATE TABLESPACE test_tablespace LOCATION XXXX/g
# columnar log for var correlation
s/(.*absolute correlation \()([0,1]\.[0-9]+)(\) of var attribute [0-9]+ is smaller than.*)/\1X\.YZ\3/g

View File

@ -645,7 +645,7 @@ alter table coltest add column x5 int default (random()*20000)::int;
analyze coltest; analyze coltest;
-- test that expressions on whole-row references are not pushed down -- test that expressions on whole-row references are not pushed down
select * from coltest where coltest = (1,1,1,1); select * from coltest where coltest = (1,1,1,1);
NOTICE: columnar planner: cannot push down clause: var is whole-row reference NOTICE: columnar planner: cannot push down clause: var is whole-row reference or system column
NOTICE: columnar planner: adding CustomScan path for coltest NOTICE: columnar planner: adding CustomScan path for coltest
DETAIL: unparameterized; 0 clauses pushed down DETAIL: unparameterized; 0 clauses pushed down
id | x1 | x2 | x3 | x5 id | x1 | x2 | x3 | x5
@ -655,7 +655,7 @@ DETAIL: unparameterized; 0 clauses pushed down
-- test that expressions on uncorrelated attributes are not pushed down -- test that expressions on uncorrelated attributes are not pushed down
set columnar.qual_pushdown_correlation to default; set columnar.qual_pushdown_correlation to default;
select * from coltest where x5 = 23484; select * from coltest where x5 = 23484;
NOTICE: columnar planner: cannot push down clause: var attribute 5 is uncorrelated NOTICE: columnar planner: cannot push down clause: absolute correlation (X.YZ) of var attribute 5 is smaller than the value configured in "columnar.qual_pushdown_correlation_threshold" (0.900)
NOTICE: columnar planner: adding CustomScan path for coltest NOTICE: columnar planner: adding CustomScan path for coltest
DETAIL: unparameterized; 0 clauses pushed down DETAIL: unparameterized; 0 clauses pushed down
id | x1 | x2 | x3 | x5 id | x1 | x2 | x3 | x5
@ -819,3 +819,250 @@ select * from numrange_test natural join numrange_test2 order by nr;
DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2; DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2;
set default_table_access_method to default; set default_table_access_method to default;
set columnar.planner_debug_level to notice;
BEGIN;
SET LOCAL columnar.stripe_row_limit = 2000;
SET LOCAL columnar.chunk_group_row_limit = 1000;
create table pushdown_test (a int, b int) using columnar;
insert into pushdown_test values (generate_series(1, 200000));
COMMIT;
SET columnar.max_custom_scan_paths TO 50;
SET columnar.qual_pushdown_correlation_threshold TO 0.0;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=2 loops=1)
Filter: ((a = 204356) OR (a = 104356) OR (a = 76556))
Rows Removed by Filter: 1998
Columnar Projected Columns: a
Columnar Chunk Group Filters: ((a = 204356) OR (a = 104356) OR (a = 76556))
Columnar Chunk Groups Removed by Filter: 198
(7 rows)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
180912
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=3 loops=1)
Filter: ((a = 194356) OR (a = 104356) OR (a = 76556))
Rows Removed by Filter: 2997
Columnar Projected Columns: a
Columnar Chunk Group Filters: ((a = 194356) OR (a = 104356) OR (a = 76556))
Columnar Chunk Groups Removed by Filter: 197
(7 rows)
SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
375268
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a > a*-1 + b;
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=0 loops=1)
Filter: ((a = 204356) OR (a > ((a * '-1'::integer) + b)))
Rows Removed by Filter: 200000
Columnar Projected Columns: a, b
(5 rows)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=38998 loops=1)
Filter: (((a > 1000) AND (a < 10000)) OR ((a > 20000) AND (a < 50000)))
Rows Removed by Filter: 2
Columnar Projected Columns: a
Columnar Chunk Group Filters: (((a > 1000) AND (a < 10000)) OR ((a > 20000) AND (a < 50000)))
Columnar Chunk Groups Removed by Filter: 161
(7 rows)
SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
1099459500
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: none of the arguments were pushdownable, due to the reason(s) given above
NOTICE: columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=200000 loops=1)
Filter: ((((a)::double precision > random()) AND (a < (2 * a))) OR (a > 100))
Columnar Projected Columns: a
(4 rows)
SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: none of the arguments were pushdownable, due to the reason(s) given above
NOTICE: columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
sum
---------------------------------------------------------------------
20000100000
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=3010 loops=1)
Filter: ((((a)::double precision > random()) AND (a <= 2000)) OR (a > 198990))
Rows Removed by Filter: 990
Columnar Projected Columns: a
Columnar Chunk Group Filters: ((a <= 2000) OR (a > 198990))
Columnar Chunk Groups Removed by Filter: 196
(7 rows)
SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
203491455
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where
(
a > random()
and
(
(a < 200 and a not in (select a from pushdown_test)) or
(a > 1000 and a < 2000)
)
)
or
(a > 200000-2010);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must not contain a subplan
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=3009 loops=1)
Filter: ((((a)::double precision > random()) AND (((a < 200) AND (NOT (SubPlan 1))) OR ((a > 1000) AND (a < 2000)))) OR (a > 197990))
Rows Removed by Filter: 1991
Columnar Projected Columns: a
Columnar Chunk Group Filters: (((a < 200) OR ((a > 1000) AND (a < 2000))) OR (a > 197990))
Columnar Chunk Groups Removed by Filter: 195
SubPlan 1
-> Materialize (actual rows=100 loops=199)
-> Custom Scan (ColumnarScan) on pushdown_test pushdown_test_1 (actual rows=199 loops=1)
Columnar Projected Columns: a
(11 rows)
SELECT sum(a) FROM pushdown_test where
(
a > random()
and
(
(a < 200 and a not in (select a from pushdown_test)) or
(a > 1000 and a < 2000)
)
)
or
(a > 200000-2010);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must not contain a subplan
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
401479455
(1 row)
create function stable_1(arg int) returns int language plpgsql STRICT IMMUTABLE as
$$ BEGIN RETURN 1+arg; END; $$;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=0 loops=1)
Filter: ((a < 6001) AND ((a)::double precision = random()) AND (a < stable_1(a)))
Rows Removed by Filter: 6000
Columnar Projected Columns: a
Columnar Chunk Group Filters: (a < 6001)
Columnar Chunk Groups Removed by Filter: 194
(7 rows)
SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
(1 row)
RESET columnar.max_custom_scan_paths;
RESET columnar.qual_pushdown_correlation_threshold;
RESET columnar.planner_debug_level;
DROP TABLE pushdown_test;

View File

@ -645,7 +645,7 @@ alter table coltest add column x5 int default (random()*20000)::int;
analyze coltest; analyze coltest;
-- test that expressions on whole-row references are not pushed down -- test that expressions on whole-row references are not pushed down
select * from coltest where coltest = (1,1,1,1); select * from coltest where coltest = (1,1,1,1);
NOTICE: columnar planner: cannot push down clause: var is whole-row reference NOTICE: columnar planner: cannot push down clause: var is whole-row reference or system column
NOTICE: columnar planner: adding CustomScan path for coltest NOTICE: columnar planner: adding CustomScan path for coltest
DETAIL: unparameterized; 0 clauses pushed down DETAIL: unparameterized; 0 clauses pushed down
id | x1 | x2 | x3 | x5 id | x1 | x2 | x3 | x5
@ -655,7 +655,7 @@ DETAIL: unparameterized; 0 clauses pushed down
-- test that expressions on uncorrelated attributes are not pushed down -- test that expressions on uncorrelated attributes are not pushed down
set columnar.qual_pushdown_correlation to default; set columnar.qual_pushdown_correlation to default;
select * from coltest where x5 = 23484; select * from coltest where x5 = 23484;
NOTICE: columnar planner: cannot push down clause: var attribute 5 is uncorrelated NOTICE: columnar planner: cannot push down clause: absolute correlation (X.YZ) of var attribute 5 is smaller than the value configured in "columnar.qual_pushdown_correlation_threshold" (0.900)
NOTICE: columnar planner: adding CustomScan path for coltest NOTICE: columnar planner: adding CustomScan path for coltest
DETAIL: unparameterized; 0 clauses pushed down DETAIL: unparameterized; 0 clauses pushed down
id | x1 | x2 | x3 | x5 id | x1 | x2 | x3 | x5
@ -819,3 +819,250 @@ select * from numrange_test natural join numrange_test2 order by nr;
DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2; DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2;
set default_table_access_method to default; set default_table_access_method to default;
set columnar.planner_debug_level to notice;
BEGIN;
SET LOCAL columnar.stripe_row_limit = 2000;
SET LOCAL columnar.chunk_group_row_limit = 1000;
create table pushdown_test (a int, b int) using columnar;
insert into pushdown_test values (generate_series(1, 200000));
COMMIT;
SET columnar.max_custom_scan_paths TO 50;
SET columnar.qual_pushdown_correlation_threshold TO 0.0;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=2 loops=1)
Filter: ((a = 204356) OR (a = 104356) OR (a = 76556))
Rows Removed by Filter: 1998
Columnar Projected Columns: a
Columnar Chunk Group Filters: ((a = 204356) OR (a = 104356) OR (a = 76556))
Columnar Chunk Groups Removed by Filter: 198
(7 rows)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
180912
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=3 loops=1)
Filter: ((a = 194356) OR (a = 104356) OR (a = 76556))
Rows Removed by Filter: 2997
Columnar Projected Columns: a
Columnar Chunk Group Filters: ((a = 194356) OR (a = 104356) OR (a = 76556))
Columnar Chunk Groups Removed by Filter: 197
(7 rows)
SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
375268
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a > a*-1 + b;
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=0 loops=1)
Filter: ((a = 204356) OR (a > ((a * '-1'::integer) + b)))
Rows Removed by Filter: 200000
Columnar Projected Columns: a, b
(5 rows)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=38998 loops=1)
Filter: (((a > 1000) AND (a < 10000)) OR ((a > 20000) AND (a < 50000)))
Rows Removed by Filter: 2
Columnar Projected Columns: a
Columnar Chunk Group Filters: (((a > 1000) AND (a < 10000)) OR ((a > 20000) AND (a < 50000)))
Columnar Chunk Groups Removed by Filter: 161
(7 rows)
SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
1099459500
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: none of the arguments were pushdownable, due to the reason(s) given above
NOTICE: columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=200000 loops=1)
Filter: ((((a)::double precision > random()) AND (a < (2 * a))) OR (a > 100))
Columnar Projected Columns: a
(4 rows)
SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: none of the arguments were pushdownable, due to the reason(s) given above
NOTICE: columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
sum
---------------------------------------------------------------------
20000100000
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=3010 loops=1)
Filter: ((((a)::double precision > random()) AND (a <= 2000)) OR (a > 198990))
Rows Removed by Filter: 990
Columnar Projected Columns: a
Columnar Chunk Group Filters: ((a <= 2000) OR (a > 198990))
Columnar Chunk Groups Removed by Filter: 196
(7 rows)
SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
203491455
(1 row)
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where
(
a > random()
and
(
(a < 200 and a not in (select a from pushdown_test)) or
(a > 1000 and a < 2000)
)
)
or
(a > 200000-2010);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must not contain a subplan
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=3009 loops=1)
Filter: ((((a)::double precision > random()) AND (((a < 200) AND (NOT (SubPlan 1))) OR ((a > 1000) AND (a < 2000)))) OR (a > 197990))
Rows Removed by Filter: 1991
Columnar Projected Columns: a
Columnar Chunk Group Filters: (((a < 200) OR ((a > 1000) AND (a < 2000))) OR (a > 197990))
Columnar Chunk Groups Removed by Filter: 195
SubPlan 1
-> Materialize (actual rows=100 loops=199)
-> Custom Scan (ColumnarScan) on pushdown_test pushdown_test_1 (actual rows=199 loops=1)
Columnar Projected Columns: a
(11 rows)
SELECT sum(a) FROM pushdown_test where
(
a > random()
and
(
(a < 200 and a not in (select a from pushdown_test)) or
(a > 1000 and a < 2000)
)
)
or
(a > 200000-2010);
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 0 clauses pushed down
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must not contain a subplan
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
401479455
(1 row)
create function stable_1(arg int) returns int language plpgsql STRICT IMMUTABLE as
$$ BEGIN RETURN 1+arg; END; $$;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
QUERY PLAN
---------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Custom Scan (ColumnarScan) on pushdown_test (actual rows=0 loops=1)
Filter: ((a < 6001) AND ((a)::double precision = random()) AND (a < stable_1(a)))
Rows Removed by Filter: 6000
Columnar Projected Columns: a
Columnar Chunk Group Filters: (a < 6001)
Columnar Chunk Groups Removed by Filter: 194
(7 rows)
SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT: Var must only reference this rel, and Expr must not reference this rel
NOTICE: columnar planner: adding CustomScan path for pushdown_test
DETAIL: unparameterized; 1 clauses pushed down
sum
---------------------------------------------------------------------
(1 row)
RESET columnar.max_custom_scan_paths;
RESET columnar.qual_pushdown_correlation_threshold;
RESET columnar.planner_debug_level;
DROP TABLE pushdown_test;

View File

@ -750,6 +750,41 @@ SELECT * FROM multi_extension.print_extension_changes();
| view public.citus_tables | view public.citus_tables
(2 rows) (2 rows)
-- not print "HINT: " to hide current lib version
\set VERBOSITY terse
CREATE TABLE columnar_table(a INT, b INT) USING columnar;
SET citus.enable_version_checks TO ON;
-- all should throw an error due to version mismatch
VACUUM FULL columnar_table;
ERROR: loaded Citus library version differs from installed extension version
INSERT INTO columnar_table SELECT i FROM generate_series(1, 10) i;
ERROR: loaded Citus library version differs from installed extension version
VACUUM columnar_table;
WARNING: loaded Citus library version differs from installed extension version
TRUNCATE columnar_table;
ERROR: loaded Citus library version differs from installed extension version
DROP TABLE columnar_table;
ERROR: loaded Citus library version differs from installed extension version
CREATE INDEX ON columnar_table (a);
ERROR: loaded Citus library version differs from installed extension version
SELECT alter_columnar_table_set('columnar_table', compression => 'pglz');
ERROR: loaded Citus library version differs from installed extension version
SELECT alter_columnar_table_reset('columnar_table');
ERROR: loaded Citus library version differs from installed extension version
INSERT INTO columnar_table SELECT * FROM columnar_table;
ERROR: loaded Citus library version differs from installed extension version
SELECT 1 FROM columnar_table; -- columnar custom scan
ERROR: loaded Citus library version differs from installed extension version
SET columnar.enable_custom_scan TO OFF;
SELECT 1 FROM columnar_table; -- seq scan
ERROR: loaded Citus library version differs from installed extension version
CREATE TABLE new_columnar_table (a int) USING columnar;
ERROR: loaded Citus library version differs from installed extension version
-- do cleanup for the rest of the tests
SET citus.enable_version_checks TO OFF;
DROP TABLE columnar_table;
RESET columnar.enable_custom_scan;
\set VERBOSITY default
-- Test downgrade to 10.0-4 from 10.1-1 -- Test downgrade to 10.0-4 from 10.1-1
ALTER EXTENSION citus UPDATE TO '10.1-1'; ALTER EXTENSION citus UPDATE TO '10.1-1';
ALTER EXTENSION citus UPDATE TO '10.0-4'; ALTER EXTENSION citus UPDATE TO '10.0-4';
@ -813,12 +848,28 @@ SELECT * FROM multi_extension.print_extension_changes();
| function worker_nextval(regclass) integer | function worker_nextval(regclass) integer
(16 rows) (16 rows)
-- Test downgrade to 10.2-1 from 10.2-2
ALTER EXTENSION citus UPDATE TO '10.2-2';
ALTER EXTENSION citus UPDATE TO '10.2-1';
-- Should be empty result since upgrade+downgrade should be a no-op
SELECT * FROM multi_extension.print_extension_changes();
previous_object | current_object
---------------------------------------------------------------------
(0 rows)
-- Snapshot of state at 10.2-2
ALTER EXTENSION citus UPDATE TO '10.2-2';
SELECT * FROM multi_extension.print_extension_changes();
previous_object | current_object
---------------------------------------------------------------------
(0 rows)
DROP TABLE multi_extension.prev_objects, multi_extension.extension_diff; DROP TABLE multi_extension.prev_objects, multi_extension.extension_diff;
-- show running version -- show running version
SHOW citus.version; SHOW citus.version;
citus.version citus.version
--------------------------------------------------------------------- ---------------------------------------------------------------------
10.2devel 10.2.1
(1 row) (1 row)
-- ensure no unexpected objects were created outside pg_catalog -- ensure no unexpected objects were created outside pg_catalog

View File

@ -265,19 +265,26 @@ SELECT * FROM columnar.stripe;
-- alter a columnar setting -- alter a columnar setting
SET columnar.chunk_group_row_limit = 1050; SET columnar.chunk_group_row_limit = 1050;
DO $proc$ -- create columnar table
BEGIN CREATE TABLE columnar_table (a int) USING columnar;
IF substring(current_Setting('server_version'), '\d+')::int >= 12 THEN -- alter a columnar table that is created by that unprivileged user
EXECUTE $$ SELECT alter_columnar_table_set('columnar_table', chunk_group_row_limit => 2000);
-- create columnar table alter_columnar_table_set
CREATE TABLE columnar_table (a int) USING columnar; ---------------------------------------------------------------------
-- alter a columnar table that is created by that unprivileged user
SELECT alter_columnar_table_set('columnar_table', chunk_group_row_limit => 2000); (1 row)
-- and drop it
DROP TABLE columnar_table; -- insert some data and read
$$; INSERT INTO columnar_table VALUES (1), (1);
END IF; SELECT * FROM columnar_table;
END$proc$; a
---------------------------------------------------------------------
1
1
(2 rows)
-- and drop it
DROP TABLE columnar_table;
-- cannot modify columnar metadata table as unprivileged user -- cannot modify columnar metadata table as unprivileged user
INSERT INTO columnar.stripe VALUES(99); INSERT INTO columnar.stripe VALUES(99);
ERROR: permission denied for table stripe ERROR: permission denied for table stripe
@ -286,6 +293,9 @@ ERROR: permission denied for table stripe
-- (since citus extension has a dependency to it) -- (since citus extension has a dependency to it)
DROP TABLE columnar.chunk; DROP TABLE columnar.chunk;
ERROR: must be owner of table chunk ERROR: must be owner of table chunk
-- cannot read columnar.chunk since it could expose chunk min/max values
SELECT * FROM columnar.chunk;
ERROR: permission denied for table chunk
-- test whether a read-only user can read from citus_tables view -- test whether a read-only user can read from citus_tables view
SELECT distribution_column FROM citus_tables WHERE table_name = 'test'::regclass; SELECT distribution_column FROM citus_tables WHERE table_name = 'test'::regclass;
distribution_column distribution_column

View File

@ -1028,6 +1028,46 @@ CREATE TABLE partitioned_users_table_2009 PARTITION OF partitioned_users_table F
CREATE TABLE partitioned_events_table_2009 PARTITION OF partitioned_events_table FOR VALUES FROM ('2017-01-01') TO ('2018-01-01'); CREATE TABLE partitioned_events_table_2009 PARTITION OF partitioned_events_table FOR VALUES FROM ('2017-01-01') TO ('2018-01-01');
INSERT INTO partitioned_events_table SELECT * FROM events_table; INSERT INTO partitioned_events_table SELECT * FROM events_table;
INSERT INTO partitioned_users_table_2009 SELECT * FROM users_table; INSERT INTO partitioned_users_table_2009 SELECT * FROM users_table;
-- test distributed partitions are indeed colocated with the parent table
CREATE TABLE sensors(measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
CREATE TABLE sensors_old PARTITION OF sensors FOR VALUES FROM ('2000-01-01') TO ('2020-01-01');
CREATE TABLE sensors_2020_01_01 PARTITION OF sensors FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
CREATE TABLE sensors_new PARTITION OF sensors DEFAULT;
SELECT create_distributed_table('sensors', 'measureid', colocate_with:='none');
create_distributed_table
---------------------------------------------------------------------
(1 row)
SELECT count(DISTINCT colocationid) FROM pg_dist_partition
WHERE logicalrelid IN ('sensors'::regclass, 'sensors_old'::regclass, 'sensors_2020_01_01'::regclass, 'sensors_new'::regclass);
count
---------------------------------------------------------------------
1
(1 row)
CREATE TABLE local_sensors(measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
CREATE TABLE local_sensors_old PARTITION OF local_sensors FOR VALUES FROM ('2000-01-01') TO ('2020-01-01');
CREATE TABLE local_sensors_2020_01_01 PARTITION OF local_sensors FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
CREATE TABLE local_sensors_new PARTITION OF local_sensors DEFAULT;
SELECT create_distributed_table('local_sensors', 'measureid', colocate_with:='sensors');
create_distributed_table
---------------------------------------------------------------------
(1 row)
SELECT count(DISTINCT colocationid) FROM pg_dist_partition
WHERE logicalrelid IN ('sensors'::regclass, 'sensors_old'::regclass, 'sensors_2020_01_01'::regclass, 'sensors_new'::regclass,
'local_sensors'::regclass, 'local_sensors_old'::regclass, 'local_sensors_2020_01_01'::regclass, 'local_sensors_new'::regclass);
count
---------------------------------------------------------------------
1
(1 row)
DROP TABLE sensors;
DROP TABLE local_sensors;
-- --
-- Complex JOINs, subqueries, UNIONs etc... -- Complex JOINs, subqueries, UNIONs etc...
-- --
@ -1298,7 +1338,7 @@ INSERT INTO multi_column_partitioning VALUES(1, 1);
INSERT INTO multi_column_partitioning_0_0_10_0 VALUES(5, -5); INSERT INTO multi_column_partitioning_0_0_10_0 VALUES(5, -5);
-- test INSERT to multi-column partitioned table where no suitable partition exists -- test INSERT to multi-column partitioned table where no suitable partition exists
INSERT INTO multi_column_partitioning VALUES(10, 1); INSERT INTO multi_column_partitioning VALUES(10, 1);
ERROR: no partition of relation "multi_column_partitioning_1660101" found for row ERROR: no partition of relation "multi_column_partitioning_1660133" found for row
DETAIL: Partition key of the failing row contains (c1, c2) = (10, 1). DETAIL: Partition key of the failing row contains (c1, c2) = (10, 1).
CONTEXT: while executing command on localhost:xxxxx CONTEXT: while executing command on localhost:xxxxx
-- test with MINVALUE/MAXVALUE -- test with MINVALUE/MAXVALUE
@ -1308,7 +1348,7 @@ INSERT INTO multi_column_partitioning VALUES(11, -11);
INSERT INTO multi_column_partitioning_10_max_20_min VALUES(19, -19); INSERT INTO multi_column_partitioning_10_max_20_min VALUES(19, -19);
-- test INSERT to multi-column partitioned table where no suitable partition exists -- test INSERT to multi-column partitioned table where no suitable partition exists
INSERT INTO multi_column_partitioning VALUES(20, -20); INSERT INTO multi_column_partitioning VALUES(20, -20);
ERROR: no partition of relation "multi_column_partitioning_1660101" found for row ERROR: no partition of relation "multi_column_partitioning_1660133" found for row
DETAIL: Partition key of the failing row contains (c1, c2) = (20, -20). DETAIL: Partition key of the failing row contains (c1, c2) = (20, -20).
CONTEXT: while executing command on localhost:xxxxx CONTEXT: while executing command on localhost:xxxxx
-- see data is loaded to multi-column partitioned table -- see data is loaded to multi-column partitioned table

View File

@ -374,3 +374,74 @@ select * from numrange_test natural join numrange_test2 order by nr;
DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2; DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2;
set default_table_access_method to default; set default_table_access_method to default;
set columnar.planner_debug_level to notice;
BEGIN;
SET LOCAL columnar.stripe_row_limit = 2000;
SET LOCAL columnar.chunk_group_row_limit = 1000;
create table pushdown_test (a int, b int) using columnar;
insert into pushdown_test values (generate_series(1, 200000));
COMMIT;
SET columnar.max_custom_scan_paths TO 50;
SET columnar.qual_pushdown_correlation_threshold TO 0.0;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a > a*-1 + b;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where
(
a > random()
and
(
(a < 200 and a not in (select a from pushdown_test)) or
(a > 1000 and a < 2000)
)
)
or
(a > 200000-2010);
SELECT sum(a) FROM pushdown_test where
(
a > random()
and
(
(a < 200 and a not in (select a from pushdown_test)) or
(a > 1000 and a < 2000)
)
)
or
(a > 200000-2010);
create function stable_1(arg int) returns int language plpgsql STRICT IMMUTABLE as
$$ BEGIN RETURN 1+arg; END; $$;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
RESET columnar.max_custom_scan_paths;
RESET columnar.qual_pushdown_correlation_threshold;
RESET columnar.planner_debug_level;
DROP TABLE pushdown_test;

View File

@ -297,6 +297,35 @@ ALTER EXTENSION citus UPDATE TO '9.5-1';
ALTER EXTENSION citus UPDATE TO '10.0-4'; ALTER EXTENSION citus UPDATE TO '10.0-4';
SELECT * FROM multi_extension.print_extension_changes(); SELECT * FROM multi_extension.print_extension_changes();
-- not print "HINT: " to hide current lib version
\set VERBOSITY terse
CREATE TABLE columnar_table(a INT, b INT) USING columnar;
SET citus.enable_version_checks TO ON;
-- all should throw an error due to version mismatch
VACUUM FULL columnar_table;
INSERT INTO columnar_table SELECT i FROM generate_series(1, 10) i;
VACUUM columnar_table;
TRUNCATE columnar_table;
DROP TABLE columnar_table;
CREATE INDEX ON columnar_table (a);
SELECT alter_columnar_table_set('columnar_table', compression => 'pglz');
SELECT alter_columnar_table_reset('columnar_table');
INSERT INTO columnar_table SELECT * FROM columnar_table;
SELECT 1 FROM columnar_table; -- columnar custom scan
SET columnar.enable_custom_scan TO OFF;
SELECT 1 FROM columnar_table; -- seq scan
CREATE TABLE new_columnar_table (a int) USING columnar;
-- do cleanup for the rest of the tests
SET citus.enable_version_checks TO OFF;
DROP TABLE columnar_table;
RESET columnar.enable_custom_scan;
\set VERBOSITY default
-- Test downgrade to 10.0-4 from 10.1-1 -- Test downgrade to 10.0-4 from 10.1-1
ALTER EXTENSION citus UPDATE TO '10.1-1'; ALTER EXTENSION citus UPDATE TO '10.1-1';
ALTER EXTENSION citus UPDATE TO '10.0-4'; ALTER EXTENSION citus UPDATE TO '10.0-4';
@ -317,6 +346,16 @@ SELECT * FROM multi_extension.print_extension_changes();
ALTER EXTENSION citus UPDATE TO '10.2-1'; ALTER EXTENSION citus UPDATE TO '10.2-1';
SELECT * FROM multi_extension.print_extension_changes(); SELECT * FROM multi_extension.print_extension_changes();
-- Test downgrade to 10.2-1 from 10.2-2
ALTER EXTENSION citus UPDATE TO '10.2-2';
ALTER EXTENSION citus UPDATE TO '10.2-1';
-- Should be empty result since upgrade+downgrade should be a no-op
SELECT * FROM multi_extension.print_extension_changes();
-- Snapshot of state at 10.2-2
ALTER EXTENSION citus UPDATE TO '10.2-2';
SELECT * FROM multi_extension.print_extension_changes();
DROP TABLE multi_extension.prev_objects, multi_extension.extension_diff; DROP TABLE multi_extension.prev_objects, multi_extension.extension_diff;
-- show running version -- show running version

View File

@ -162,19 +162,15 @@ SELECT * FROM columnar.stripe;
-- alter a columnar setting -- alter a columnar setting
SET columnar.chunk_group_row_limit = 1050; SET columnar.chunk_group_row_limit = 1050;
DO $proc$ -- create columnar table
BEGIN CREATE TABLE columnar_table (a int) USING columnar;
IF substring(current_Setting('server_version'), '\d+')::int >= 12 THEN -- alter a columnar table that is created by that unprivileged user
EXECUTE $$ SELECT alter_columnar_table_set('columnar_table', chunk_group_row_limit => 2000);
-- create columnar table -- insert some data and read
CREATE TABLE columnar_table (a int) USING columnar; INSERT INTO columnar_table VALUES (1), (1);
-- alter a columnar table that is created by that unprivileged user SELECT * FROM columnar_table;
SELECT alter_columnar_table_set('columnar_table', chunk_group_row_limit => 2000); -- and drop it
-- and drop it DROP TABLE columnar_table;
DROP TABLE columnar_table;
$$;
END IF;
END$proc$;
-- cannot modify columnar metadata table as unprivileged user -- cannot modify columnar metadata table as unprivileged user
INSERT INTO columnar.stripe VALUES(99); INSERT INTO columnar.stripe VALUES(99);
@ -183,6 +179,8 @@ INSERT INTO columnar.stripe VALUES(99);
-- (since citus extension has a dependency to it) -- (since citus extension has a dependency to it)
DROP TABLE columnar.chunk; DROP TABLE columnar.chunk;
-- cannot read columnar.chunk since it could expose chunk min/max values
SELECT * FROM columnar.chunk;
-- test whether a read-only user can read from citus_tables view -- test whether a read-only user can read from citus_tables view
SELECT distribution_column FROM citus_tables WHERE table_name = 'test'::regclass; SELECT distribution_column FROM citus_tables WHERE table_name = 'test'::regclass;

View File

@ -638,6 +638,35 @@ CREATE TABLE partitioned_events_table_2009 PARTITION OF partitioned_events_table
INSERT INTO partitioned_events_table SELECT * FROM events_table; INSERT INTO partitioned_events_table SELECT * FROM events_table;
INSERT INTO partitioned_users_table_2009 SELECT * FROM users_table; INSERT INTO partitioned_users_table_2009 SELECT * FROM users_table;
-- test distributed partitions are indeed colocated with the parent table
CREATE TABLE sensors(measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
CREATE TABLE sensors_old PARTITION OF sensors FOR VALUES FROM ('2000-01-01') TO ('2020-01-01');
CREATE TABLE sensors_2020_01_01 PARTITION OF sensors FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
CREATE TABLE sensors_new PARTITION OF sensors DEFAULT;
SELECT create_distributed_table('sensors', 'measureid', colocate_with:='none');
SELECT count(DISTINCT colocationid) FROM pg_dist_partition
WHERE logicalrelid IN ('sensors'::regclass, 'sensors_old'::regclass, 'sensors_2020_01_01'::regclass, 'sensors_new'::regclass);
CREATE TABLE local_sensors(measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
CREATE TABLE local_sensors_old PARTITION OF local_sensors FOR VALUES FROM ('2000-01-01') TO ('2020-01-01');
CREATE TABLE local_sensors_2020_01_01 PARTITION OF local_sensors FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
CREATE TABLE local_sensors_new PARTITION OF local_sensors DEFAULT;
SELECT create_distributed_table('local_sensors', 'measureid', colocate_with:='sensors');
SELECT count(DISTINCT colocationid) FROM pg_dist_partition
WHERE logicalrelid IN ('sensors'::regclass, 'sensors_old'::regclass, 'sensors_2020_01_01'::regclass, 'sensors_new'::regclass,
'local_sensors'::regclass, 'local_sensors_old'::regclass, 'local_sensors_2020_01_01'::regclass, 'local_sensors_new'::regclass);
DROP TABLE sensors;
DROP TABLE local_sensors;
-- --
-- Complex JOINs, subqueries, UNIONs etc... -- Complex JOINs, subqueries, UNIONs etc...
-- --