解决多行插入包含右值引用时存在的问题

This commit is contained in:
laishenghao
2023-09-26 19:51:10 +08:00
parent faf7ae5eb0
commit bc4e1013bb
7 changed files with 90 additions and 26 deletions

View File

@ -1594,17 +1594,16 @@ static void CheckUnsupportInsertSelectClause(Query* query)
}
static void SetInsertAttrnoState(ParseState* pstate, List* attrnos)
static void SetInsertAttrnoState(ParseState* pstate, List* attrnos, int exprLen)
{
RightRefState* rstate = pstate->rightRefState;
Relation relation = (Relation)linitial(pstate->p_target_relation);
rstate->colCnt = RelationGetNumberOfAttributes(relation);
int len = list_length(attrnos);
rstate->explicitAttrLen = len;
rstate->explicitAttrNos = (int*)palloc0(sizeof(int) * len);
rstate->explicitAttrLen = exprLen;
rstate->explicitAttrNos = (int*)palloc0(sizeof(int) * exprLen);
ListCell* attr = list_head(attrnos);
for (int i = 0; i < len; ++i) {
for (int i = 0; i < exprLen; ++i) {
rstate->explicitAttrNos[i] = lfirst_int(attr);
attr = lnext(attr);
}
@ -1854,8 +1853,6 @@ static Query* transformInsertStmt(ParseState* pstate, InsertStmt* stmt)
/* Validate stmt->cols list, or build default list if no list given */
icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
SetInsertAttrnoState(pstate, attrnos);
AssertEreport(list_length(icolumns) == list_length(attrnos), MOD_OPT, "list length inconsistent");
@ -2179,6 +2176,10 @@ static Query* transformInsertStmt(ParseState* pstate, InsertStmt* stmt)
exprList = transformInsertRow(pstate, exprList, stmt->cols, icolumns, attrnos);
}
if (rightRefState->isSupported) {
SetInsertAttrnoState(pstate, attrnos, list_length(exprList));
}
/*
* Generate query's target list using the computed list of expressions.
* Also, mark all the target columns as needing insert permissions.

View File

@ -632,7 +632,7 @@ static Datum ExecEvalScalarVar(ExprState* exprstate, ExprContext* econtext, bool
RightRefState* refState = econtext->rightRefState;
int index = attnum - 1;
if (refState && refState->values &&
(IS_ENABLE_INSERT_RIGHT_REF(refState) ||
((slot == nullptr && IS_ENABLE_INSERT_RIGHT_REF(refState)) ||
(IS_ENABLE_UPSERT_RIGHT_REF(refState) && refState->hasExecs[index] && index < refState->colCnt))) {
*isNull = refState->isNulls[index];
return refState->values[index];
@ -6872,7 +6872,7 @@ static bool ExecTargetList(List* targetlist, ExprContext* econtext, Datum* value
SortTargetListAsArray(refState, targetlist, targetArr);
InitOutputValues(refState, targetArr, values, isnull, targetCount, hasExecs);
InitOutputValues(refState, values, isnull, hasExecs);
/*
* evaluate all the expressions in the target list

View File

@ -2825,8 +2825,7 @@ Tuple ReplaceTupleNullCol(TupleDesc tupleDesc, TupleTableSlot *slot)
}
void InitOutputValues(RightRefState* refState, GenericExprState* targetArr[],
Datum* values, bool* isnull, int targetCount, bool* hasExecs)
void InitOutputValues(RightRefState* refState, Datum* values, bool* isnull, bool* hasExecs)
{
if (!IS_ENABLE_RIGHT_REF(refState)) {
return;
@ -2835,13 +2834,13 @@ void InitOutputValues(RightRefState* refState, GenericExprState* targetArr[],
refState->values = values;
refState->isNulls = isnull;
refState->hasExecs = hasExecs;
int colCnt = refState->colCnt;
const int colCnt = refState->colCnt;
for (int i = 0; i < colCnt; ++i) {
hasExecs[i] = false;
}
if (IS_ENABLE_INSERT_RIGHT_REF(refState)) {
for (int i = 0; i < targetCount; ++i) {
for (int i = 0; i < colCnt; ++i) {
Const* con = refState->constValues[i];
if (con) {
values[i] = con->constvalue;

View File

@ -125,30 +125,31 @@ static TupleTableSlot* ValuesNext(ValuesScanState* node)
RightRefState* refState = econtext->rightRefState;
int targetCount = list_length(expr_state_list);
GenericExprState* targetArr[targetCount];
int colCnt = (IS_ENABLE_RIGHT_REF(refState) && refState->colCnt > 0) ? refState->colCnt : 1;
bool hasExecs[colCnt];
SortTargetListAsArray(refState, expr_state_list, targetArr);
InitOutputValues(refState, targetArr, values, is_null, targetCount, hasExecs);
Datum rightRefValues[colCnt];
bool rightRefIsNulls[colCnt];
InitOutputValues(refState, rightRefValues, rightRefIsNulls, hasExecs);
resind = 0;
foreach (lc, expr_state_list) {
ExprState* exprState = (ExprState*)lfirst(lc);
values[resind] = ExecEvalExpr(exprState, econtext, &is_null[resind]);
if (IS_ENABLE_RIGHT_REF(refState) && resind < refState->colCnt) {
hasExecs[resind] = true;
if (unlikely(IS_ENABLE_INSERT_RIGHT_REF(refState) && resind < refState->explicitAttrLen)) {
int idx = refState->explicitAttrNos[resind] - 1;
hasExecs[idx] = true;
rightRefValues[idx] = values[resind];
rightRefIsNulls[idx] = is_null[resind];
}
resind++;
}
if (IS_ENABLE_RIGHT_REF(econtext->rightRefState)) {
econtext->rightRefState->values = nullptr;
econtext->rightRefState->isNulls = nullptr;
econtext->rightRefState->hasExecs = nullptr;
if (unlikely(IS_ENABLE_RIGHT_REF(refState))) {
refState->values = nullptr;
refState->isNulls = nullptr;
refState->hasExecs = nullptr;
}
MemoryContextSwitchTo(old_context);

View File

@ -507,8 +507,7 @@ extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid, bool markdropped
extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, const TableAmRoutine *tam_ops = TableAmHeap);
extern TupleDesc ExecTypeFromExprList(List *exprList, List *namesList, const TableAmRoutine *tam_ops = TableAmHeap);
extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
extern void InitOutputValues(RightRefState *refState, GenericExprState *targetArr[], Datum *values, bool *isnull,
int targetCount, bool *hasExecs);
extern void InitOutputValues(RightRefState* refState, Datum* values, bool* isnull, bool* hasExecs);
extern void SortTargetListAsArray(RightRefState *refState, List *targetList, GenericExprState *targetArr[]);
typedef struct TupOutputState {

View File

@ -450,6 +450,24 @@ CREATE TABLE t2 (
INSERT INTO t2 VALUES (6, 6) ON DUPLICATE KEY UPDATE t2.col1 = t2.col2 + 1;
INSERT INTO t2 VALUES (6, 6) ON DUPLICATE KEY UPDATE t2.col1 = extract(century from col4) * 100 + extract(isodow from col4);
-- multi values case1
create table t_multi_values(a int not null primary key, b char(10));
insert into t_multi_values values (1);
insert into t_multi_values values (a+2);
insert into t_multi_values values (a+5),(a+6);
insert into t_multi_values values (a+7, b),(a+8, concat(b, ' not display')), (a+9 + a * 3, b),(a + 10 + a * 3, 'display');
select * from t_multi_values order by a;
-- multi values case2
create table t_multi_values2(f1 int primary key, f2 int, f3 int);
insert into t_multi_values2(f1, f3, f2) VALUES(1, f1 + 2, f3 + 3),(2, f1 + 2, f3 + 3),(3, f1 + 2, f3 + 3),(4, f1 + 2, f3 + 3);
select * from t_multi_values2 order by f1;
-- multi values case3
create table t_multi_values3(f1 int primary key, f2 int, f3 int);
insert into t_multi_values3(f1, f3) VALUES(1, f1 + 2),(2, f1 + 2),(3, f1 + 2),(4, f1 + 2);
select * from t_multi_values3 order by f1;
-- jdbc case
DROP USER IF EXISTS rightref CASCADE;
CREATE USER rightref WITH PASSWORD 'rightref@123';

View File

@ -625,6 +625,52 @@ NOTICE: CREATE TABLE will create implicit sequence "t2_col5_seq" for serial col
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t2_pkey" for table "t2"
INSERT INTO t2 VALUES (6, 6) ON DUPLICATE KEY UPDATE t2.col1 = t2.col2 + 1;
INSERT INTO t2 VALUES (6, 6) ON DUPLICATE KEY UPDATE t2.col1 = extract(century from col4) * 100 + extract(isodow from col4);
-- multi values case1
create table t_multi_values(a int not null primary key, b char(10));
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t_multi_values_pkey" for table "t_multi_values"
insert into t_multi_values values (1);
insert into t_multi_values values (a+2);
insert into t_multi_values values (a+5),(a+6);
insert into t_multi_values values (a+7, b),(a+8, concat(b, ' not display')), (a+9 + a * 3, b),(a + 10 + a * 3, 'display');
select * from t_multi_values order by a;
a | b
----+------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 | display
(8 rows)
-- multi values case2
create table t_multi_values2(f1 int primary key, f2 int, f3 int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t_multi_values2_pkey" for table "t_multi_values2"
insert into t_multi_values2(f1, f3, f2) VALUES(1, f1 + 2, f3 + 3),(2, f1 + 2, f3 + 3),(3, f1 + 2, f3 + 3),(4, f1 + 2, f3 + 3);
select * from t_multi_values2 order by f1;
f1 | f2 | f3
----+----+----
1 | 6 | 3
2 | 7 | 4
3 | 8 | 5
4 | 9 | 6
(4 rows)
-- multi values case3
create table t_multi_values3(f1 int primary key, f2 int, f3 int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t_multi_values3_pkey" for table "t_multi_values3"
insert into t_multi_values3(f1, f3) VALUES(1, f1 + 2),(2, f1 + 2),(3, f1 + 2),(4, f1 + 2);
select * from t_multi_values3 order by f1;
f1 | f2 | f3
----+----+----
1 | | 3
2 | | 4
3 | | 5
4 | | 6
(4 rows)
-- jdbc case
DROP USER IF EXISTS rightref CASCADE;
NOTICE: role "rightref" does not exist, skipping