解决多行插入包含右值引用时存在的问题
This commit is contained in:
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user