diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index b00bca043..9fa5ca49b 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -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. diff --git a/src/gausskernel/runtime/executor/execQual.cpp b/src/gausskernel/runtime/executor/execQual.cpp index a5e822161..25edc6283 100644 --- a/src/gausskernel/runtime/executor/execQual.cpp +++ b/src/gausskernel/runtime/executor/execQual.cpp @@ -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 diff --git a/src/gausskernel/runtime/executor/execUtils.cpp b/src/gausskernel/runtime/executor/execUtils.cpp index 06d632b61..a07903b34 100644 --- a/src/gausskernel/runtime/executor/execUtils.cpp +++ b/src/gausskernel/runtime/executor/execUtils.cpp @@ -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; diff --git a/src/gausskernel/runtime/executor/nodeValuesscan.cpp b/src/gausskernel/runtime/executor/nodeValuesscan.cpp index 210b66a17..606836940 100644 --- a/src/gausskernel/runtime/executor/nodeValuesscan.cpp +++ b/src/gausskernel/runtime/executor/nodeValuesscan.cpp @@ -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); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 49358b835..bfcb01803 100755 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -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 { diff --git a/src/test/regress/input/insert_right_ref.source b/src/test/regress/input/insert_right_ref.source index da39b5356..8c6101202 100644 --- a/src/test/regress/input/insert_right_ref.source +++ b/src/test/regress/input/insert_right_ref.source @@ -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'; diff --git a/src/test/regress/output/insert_right_ref.source b/src/test/regress/output/insert_right_ref.source index 4e05f4ee5..c9d919864 100644 --- a/src/test/regress/output/insert_right_ref.source +++ b/src/test/regress/output/insert_right_ref.source @@ -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