Skip to content

Commit c7a55c8

Browse files
authored
Merge branch 'main' into remove-stats-collector
2 parents b65096b + 95477e6 commit c7a55c8

83 files changed

Lines changed: 2256 additions & 902 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build_and_test.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
style_checker_image_name: "ghcr.io/citusdata/stylechecker"
3333
style_checker_tools_version: "0.8.18"
3434
sql_snapshot_pg_version: "17.6"
35-
image_suffix: "-v4df94a0"
35+
image_suffix: "-va20872f"
3636
pg15_version: '{ "major": "15", "full": "15.14" }'
3737
pg16_version: '{ "major": "16", "full": "16.10" }'
3838
pg17_version: '{ "major": "17", "full": "17.6" }'
@@ -358,14 +358,20 @@ jobs:
358358
flags: ${{ env.old_pg_major }}_${{ env.new_pg_major }}_upgrade
359359
codecov_token: ${{ secrets.CODECOV_TOKEN }}
360360
test-citus-upgrade:
361-
name: PG${{ fromJson(needs.params.outputs.pg15_version).major }} - check-citus-upgrade
361+
name: PG${{ fromJson(matrix.pg_version).major }} - check-citus-upgrade
362362
runs-on: ubuntu-latest
363363
container:
364-
image: "${{ needs.params.outputs.citusupgrade_image_name }}:${{ fromJson(needs.params.outputs.pg15_version).full }}${{ needs.params.outputs.image_suffix }}"
364+
image: "${{ needs.params.outputs.citusupgrade_image_name }}:${{ fromJson(matrix.pg_version).full }}${{ needs.params.outputs.image_suffix }}"
365365
options: --user root
366366
needs:
367367
- params
368368
- build
369+
strategy:
370+
fail-fast: false
371+
matrix:
372+
pg_version:
373+
- ${{ needs.params.outputs.pg15_version }}
374+
- ${{ needs.params.outputs.pg16_version }}
369375
steps:
370376
- uses: actions/checkout@v4
371377
- uses: "./.github/actions/setup_extension"
@@ -374,7 +380,7 @@ jobs:
374380
- name: Install and test citus upgrade
375381
run: |-
376382
# run make check-citus-upgrade for all citus versions
377-
# the image has ${CITUS_VERSIONS} set with all verions it contains the binaries of
383+
# the image has ${CITUS_VERSIONS} set with all versions it contains the binaries of
378384
for citus_version in ${CITUS_VERSIONS}; do \
379385
gosu circleci \
380386
make -C src/test/regress \
@@ -385,7 +391,7 @@ jobs:
385391
citus-post-tar=${GITHUB_WORKSPACE}/install-$PG_MAJOR.tar; \
386392
done;
387393
# run make check-citus-upgrade-mixed for all citus versions
388-
# the image has ${CITUS_VERSIONS} set with all verions it contains the binaries of
394+
# the image has ${CITUS_VERSIONS} set with all versions it contains the binaries of
389395
for citus_version in ${CITUS_VERSIONS}; do \
390396
gosu circleci \
391397
make -C src/test/regress \

.github/workflows/codeql.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ jobs:
6060
libzstd-dev \
6161
libzstd1 \
6262
lintian \
63-
postgresql-server-dev-15 \
64-
postgresql-server-dev-all \
63+
postgresql-server-dev-17 \
6564
python3-pip \
6665
python3-setuptools \
6766
wget \

CHANGELOG.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,48 @@
1+
### citus v13.1.1 (Oct 1st, 2025) ###
2+
3+
* Adds support for latest PG minors: 14.19, 15.14, 16.10 (#8142)
4+
5+
* Fixes an assertion failure when an expression in the query references
6+
a CTE (#8106)
7+
8+
* Fixes a bug that causes an unexpected error when executing
9+
repartitioned MERGE (#8201)
10+
11+
* Fixes a bug that causes allowing UPDATE / MERGE queries that may
12+
change the distribution column value (#8214)
13+
14+
* Updates dynamic_library_path automatically when CDC is enabled (#8025)
15+
16+
### citus v13.0.5 (Oct 1st, 2025) ###
17+
18+
* Adds support for latest PG minors: 14.19, 15.14, 16.10 (#7986, #8142)
19+
20+
* Fixes a bug that causes an unexpected error when executing
21+
repartitioned MERGE (#8201)
22+
23+
* Fixes a bug that causes allowing UPDATE / MERGE queries that may
24+
change the distribution column value (#8214)
25+
26+
* Fixes a bug in redundant WHERE clause detection (#8162)
27+
28+
* Updates dynamic_library_path automatically when CDC is enabled (#8025)
29+
30+
### citus v12.1.10 (Oct 1, 2025) ###
31+
32+
* Adds support for latest PG minors: 14.19, 15.14, 16.10 (#7986, #8142)
33+
34+
* Fixes a bug that causes allowing UPDATE / MERGE queries that may
35+
change the distribution column value (#8214)
36+
37+
* Fixes an assertion failure that happens when querying a view that is
38+
defined on distributed tables (#8136)
39+
40+
### citus v12.1.9 (Sep 3, 2025) ###
41+
42+
* Adds a GUC for queries with outer joins and pseudoconstant quals (#8163)
43+
44+
* Updates dynamic_library_path automatically when CDC is enabled (#7715)
45+
146
### citus v13.2.0 (August 18, 2025) ###
247

348
* Adds `citus_add_clone_node()`, `citus_add_clone_node_with_nodeid()`,

src/backend/columnar/columnar_metadata.c

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,9 +1394,6 @@ static StripeMetadata *
13941394
UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, uint64 fileOffset,
13951395
uint64 dataLength, uint64 rowCount, uint64 chunkCount)
13961396
{
1397-
SnapshotData dirtySnapshot;
1398-
InitDirtySnapshot(dirtySnapshot);
1399-
14001397
ScanKeyData scanKey[2];
14011398
ScanKeyInit(&scanKey[0], Anum_columnar_stripe_storageid,
14021399
BTEqualStrategyNumber, F_INT8EQ, Int64GetDatum(storageId));
@@ -1405,23 +1402,16 @@ UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, uint64 fileOffset,
14051402

14061403
Oid columnarStripesOid = ColumnarStripeRelationId();
14071404

1408-
#if PG_VERSION_NUM >= 180000
1409-
1410-
/* CatalogTupleUpdate performs a normal heap UPDATE → RowExclusiveLock */
1411-
const LOCKMODE openLockMode = RowExclusiveLock;
1412-
#else
1413-
1414-
/* In‑place update never changed tuple length → AccessShareLock was enough */
1415-
const LOCKMODE openLockMode = AccessShareLock;
1416-
#endif
1417-
1418-
Relation columnarStripes = table_open(columnarStripesOid, openLockMode);
1405+
Relation columnarStripes = table_open(columnarStripesOid, AccessShareLock);
14191406
TupleDesc tupleDescriptor = RelationGetDescr(columnarStripes);
14201407

14211408
Oid indexId = ColumnarStripePKeyIndexRelationId();
14221409
bool indexOk = OidIsValid(indexId);
1423-
SysScanDesc scanDescriptor = systable_beginscan(columnarStripes, indexId, indexOk,
1424-
&dirtySnapshot, 2, scanKey);
1410+
1411+
void *state;
1412+
HeapTuple tuple;
1413+
systable_inplace_update_begin(columnarStripes, indexId, indexOk, NULL,
1414+
2, scanKey, &tuple, &state);
14251415

14261416
static bool loggedSlowMetadataAccessWarning = false;
14271417
if (!indexOk && !loggedSlowMetadataAccessWarning)
@@ -1430,15 +1420,19 @@ UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, uint64 fileOffset,
14301420
loggedSlowMetadataAccessWarning = true;
14311421
}
14321422

1433-
HeapTuple oldTuple = systable_getnext(scanDescriptor);
1434-
if (!HeapTupleIsValid(oldTuple))
1423+
if (!HeapTupleIsValid(tuple))
14351424
{
14361425
ereport(ERROR, (errmsg("attempted to modify an unexpected stripe, "
14371426
"columnar storage with id=" UINT64_FORMAT
14381427
" does not have stripe with id=" UINT64_FORMAT,
14391428
storageId, stripeId)));
14401429
}
14411430

1431+
/*
1432+
* systable_inplace_update_finish already doesn't allow changing size of the original
1433+
* tuple, so we don't allow setting any Datum's to NULL values.
1434+
*/
1435+
14421436
Datum *newValues = (Datum *) palloc(tupleDescriptor->natts * sizeof(Datum));
14431437
bool *newNulls = (bool *) palloc0(tupleDescriptor->natts * sizeof(bool));
14441438
bool *update = (bool *) palloc0(tupleDescriptor->natts * sizeof(bool));
@@ -1453,43 +1447,21 @@ UpdateStripeMetadataRow(uint64 storageId, uint64 stripeId, uint64 fileOffset,
14531447
newValues[Anum_columnar_stripe_row_count - 1] = UInt64GetDatum(rowCount);
14541448
newValues[Anum_columnar_stripe_chunk_count - 1] = Int32GetDatum(chunkCount);
14551449

1456-
HeapTuple modifiedTuple = heap_modify_tuple(oldTuple,
1457-
tupleDescriptor,
1458-
newValues,
1459-
newNulls,
1460-
update);
1450+
tuple = heap_modify_tuple(tuple,
1451+
tupleDescriptor,
1452+
newValues,
1453+
newNulls,
1454+
update);
14611455

1462-
#if PG_VERSION_NUM < PG_VERSION_18
1456+
systable_inplace_update_finish(state, tuple);
14631457

1464-
/*
1465-
* heap_inplace_update already doesn't allow changing size of the original
1466-
* tuple, so we don't allow setting any Datum's to NULL values.
1467-
*/
1468-
heap_inplace_update(columnarStripes, modifiedTuple);
1469-
1470-
/*
1471-
* Existing tuple now contains modifications, because we used
1472-
* heap_inplace_update().
1473-
*/
1474-
HeapTuple newTuple = oldTuple;
1475-
#else
1476-
1477-
/* Regular catalog UPDATE keeps indexes in sync */
1478-
CatalogTupleUpdate(columnarStripes, &oldTuple->t_self, modifiedTuple);
1479-
HeapTuple newTuple = modifiedTuple;
1480-
#endif
1458+
StripeMetadata *modifiedStripeMetadata = BuildStripeMetadata(columnarStripes,
1459+
tuple);
14811460

14821461
CommandCounterIncrement();
14831462

1484-
/*
1485-
* Must not pass modifiedTuple, because BuildStripeMetadata expects a real
1486-
* heap tuple with MVCC fields.
1487-
*/
1488-
StripeMetadata *modifiedStripeMetadata =
1489-
BuildStripeMetadata(columnarStripes, newTuple);
1490-
1491-
systable_endscan(scanDescriptor);
1492-
table_close(columnarStripes, openLockMode);
1463+
heap_freetuple(tuple);
1464+
table_close(columnarStripes, AccessShareLock);
14931465

14941466
pfree(newValues);
14951467
pfree(newNulls);

src/backend/columnar/columnar_tableam.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1245,10 +1245,14 @@ LogRelationStats(Relation rel, int elevel)
12451245
foreach(stripeMetadataCell, stripeList)
12461246
{
12471247
StripeMetadata *stripe = lfirst(stripeMetadataCell);
1248+
1249+
Snapshot snapshot = RegisterSnapshot(GetTransactionSnapshot());
12481250
StripeSkipList *skiplist = ReadStripeSkipList(relfilelocator, stripe->id,
12491251
RelationGetDescr(rel),
12501252
stripe->chunkCount,
1251-
GetTransactionSnapshot());
1253+
snapshot);
1254+
UnregisterSnapshot(snapshot);
1255+
12521256
for (uint32 column = 0; column < skiplist->columnCount; column++)
12531257
{
12541258
bool attrDropped = Attr(tupdesc, column)->attisdropped;

src/backend/distributed/commands/common.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "nodes/parsenodes.h"
2020
#include "tcop/utility.h"
2121

22+
#include "distributed/citus_depended_object.h"
2223
#include "distributed/commands.h"
2324
#include "distributed/commands/utility_hook.h"
2425
#include "distributed/deparser.h"
@@ -63,6 +64,13 @@ PostprocessCreateDistributedObjectFromCatalogStmt(Node *stmt, const char *queryS
6364
return NIL;
6465
}
6566

67+
if (ops->qualify && DistOpsValidityState(stmt, ops) ==
68+
ShouldQualifyAfterLocalCreation)
69+
{
70+
/* qualify the statement after local creation */
71+
ops->qualify(stmt);
72+
}
73+
6674
List *addresses = GetObjectAddressListFromParseTree(stmt, false, true);
6775

6876
/* the code-path only supports a single object */

src/backend/distributed/deparser/qualify_statistics_stmt.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ QualifyCreateStatisticsStmt(Node *node)
3434
{
3535
CreateStatsStmt *stmt = castNode(CreateStatsStmt, node);
3636

37-
RangeVar *relation = (RangeVar *) linitial(stmt->relations);
37+
Node *relationNode = (Node *) linitial(stmt->relations);
38+
39+
if (!IsA(relationNode, RangeVar))
40+
{
41+
return;
42+
}
43+
44+
RangeVar *relation = (RangeVar *) relationNode;
3845

3946
if (relation->schemaname == NULL)
4047
{

src/backend/distributed/planner/distributed_planner.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "postgres.h"
1414

1515
#include "funcapi.h"
16+
#include "miscadmin.h"
1617

1718
#include "access/htup_details.h"
1819
#include "access/xact.h"
@@ -144,6 +145,9 @@ static void ConcatenateRTablesAndPerminfos(PlannedStmt *mainPlan,
144145
static bool CheckPostPlanDistribution(DistributedPlanningContext *planContext,
145146
bool isDistributedQuery,
146147
List *rangeTableList);
148+
#if PG_VERSION_NUM >= PG_VERSION_18
149+
static int DisableSelfJoinElimination(void);
150+
#endif
147151

148152
/* Distributed planner hook */
149153
PlannedStmt *
@@ -155,6 +159,9 @@ distributed_planner(Query *parse,
155159
bool needsDistributedPlanning = false;
156160
bool fastPathRouterQuery = false;
157161
FastPathRestrictionContext fastPathContext = { 0 };
162+
#if PG_VERSION_NUM >= PG_VERSION_18
163+
int saveNestLevel = -1;
164+
#endif
158165

159166
List *rangeTableList = ExtractRangeTableEntryList(parse);
160167

@@ -218,6 +225,10 @@ distributed_planner(Query *parse,
218225
bool setPartitionedTablesInherited = false;
219226
AdjustPartitioningForDistributedPlanning(rangeTableList,
220227
setPartitionedTablesInherited);
228+
229+
#if PG_VERSION_NUM >= PG_VERSION_18
230+
saveNestLevel = DisableSelfJoinElimination();
231+
#endif
221232
}
222233
}
223234

@@ -264,6 +275,13 @@ distributed_planner(Query *parse,
264275
planContext.plan = standard_planner(planContext.query, NULL,
265276
planContext.cursorOptions,
266277
planContext.boundParams);
278+
#if PG_VERSION_NUM >= PG_VERSION_18
279+
if (needsDistributedPlanning)
280+
{
281+
Assert(saveNestLevel > 0);
282+
AtEOXact_GUC(true, saveNestLevel);
283+
}
284+
#endif
267285
needsDistributedPlanning = CheckPostPlanDistribution(&planContext,
268286
needsDistributedPlanning,
269287
rangeTableList);
@@ -2791,3 +2809,27 @@ CheckPostPlanDistribution(DistributedPlanningContext *planContext, bool
27912809

27922810
return isDistributedQuery;
27932811
}
2812+
2813+
2814+
#if PG_VERSION_NUM >= PG_VERSION_18
2815+
2816+
/*
2817+
* DisableSelfJoinElimination is used to prevent self join elimination
2818+
* during distributed query planning to ensure shard queries are correctly
2819+
* generated. PG18's self join elimination (fc069a3a6) changes the Query
2820+
* in a way that can cause problems for queries with a mix of Citus and
2821+
* Postgres tables. Self join elimination is allowed on Postgres tables
2822+
* only so queries involving shards get the benefit of it.
2823+
*/
2824+
static int
2825+
DisableSelfJoinElimination(void)
2826+
{
2827+
int NestLevel = NewGUCNestLevel();
2828+
set_config_option("enable_self_join_elimination", "off",
2829+
(superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION,
2830+
GUC_ACTION_LOCAL, true, 0, false);
2831+
return NestLevel;
2832+
}
2833+
2834+
2835+
#endif

0 commit comments

Comments
 (0)