Enhance insert/select planner to handle nextval expressions correctly

m3hm3t/issue_7784
Mehmet Yilmaz 2025-03-14 10:17:35 +00:00
parent 12651a2320
commit 44f2b92648
2 changed files with 73 additions and 0 deletions

1
citus-tools Submodule

@ -0,0 +1 @@
Subproject commit 3376bd6845f0614908ed304f5033bd644c82d3bf

View File

@ -28,6 +28,7 @@
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/fmgroids.h"
#include "pg_version_constants.h"
@ -107,6 +108,7 @@ static void ResetTargetEntryResno(List *targetList);
static void ProcessEntryPair(TargetEntry *insertEntry, TargetEntry *selectEntry,
Form_pg_attribute attr, int targetEntryIndex,
List **projectedEntries, List **nonProjectedEntries);
static bool IsNextvalExpression(Expr *expr);
/* depth of current insert/select planner. */
@ -1699,6 +1701,44 @@ ProcessEntryPair(TargetEntry *insertEntry, TargetEntry *selectEntry,
Form_pg_attribute attr, int targetEntryIndex,
List **projectedEntries, List **nonProjectedEntries)
{
/* Check if it's nextval(...) */
if (IsNextvalExpression((Expr *) selectEntry->expr))
{
/*
* The real nextval(...) TLE belongs in nonProjectedEntries
* so that the coordinator (not the worker) will evaluate it.
*/
TargetEntry *coordinatorEntry = copyObject(selectEntry);
/*
* If there's a type mismatch, we might still do a cast. For now, assume
* nextval returns INT8. If your target column is INT4, you can do a cast
* as well. Or rely on subsequent code to do that if needed.
*/
if (attr->atttypid != exprType((Node *) coordinatorEntry->expr))
{
coordinatorEntry->expr =
CastExpr((Expr *) coordinatorEntry->expr,
exprType((Node *) coordinatorEntry->expr),
attr->atttypid,
attr->attcollation,
attr->atttypmod);
}
/* Optionally rename the coordinator entry so it won't conflict with placeholders */
coordinatorEntry->resname = pstrdup("coordinator_nextval");
/*
* (C) Add them to the respective lists:
* - real nextval entry goes to nonProjectedEntries (the coordinator aggregator).
*/
*nonProjectedEntries = lappend(*nonProjectedEntries, coordinatorEntry);
return; /* done handling nextval */
}
Oid effectiveSourceType = exprType((Node *) selectEntry->expr);
Oid targetType = attr->atttypid;
@ -1754,6 +1794,38 @@ ResetTargetEntryResno(List *targetList)
}
/*
* IsNextvalExpression returns true if `expr` is either a NextValueExpr
* or a FuncExpr calling nextval(...).
*/
static bool
IsNextvalExpression(Expr *expr)
{
if (expr == NULL)
{
return false;
}
/* e.g. identity column usage */
if (IsA(expr, NextValueExpr))
{
return true;
}
/* or an explicit nextval() call */
if (IsA(expr, FuncExpr))
{
FuncExpr *funcExpr = (FuncExpr *) expr;
if (funcExpr->funcid == F_NEXTVAL) /* #include "utils/builtins.h" for F_NEXTVAL */
{
return true;
}
}
return false;
}
/*
* Looks up the nextval(regclass) function in pg_proc, returning its actual
* rettype. In a standard build, that will be INT8OID, but this is more robust.