!1908 issue处理:ignore_hint在interval分区表中插入null值时,报error而不是warning
Merge pull request !1908 from zhangzhixian/issue_handling_for_interval_partition
This commit is contained in:
@ -6260,7 +6260,7 @@ Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
|
||||
UnlockRelationForAccessIntervalPartTabIfHeld(rel);
|
||||
/* it will accept invalidation messages generated by other sessions in lockRelationForAddIntervalPartition. */
|
||||
LockRelationForAddIntervalPartition(rel);
|
||||
partitionRoutingForTuple(rel, insertTuple, u_sess->catalog_cxt.route);
|
||||
partitionRoutingForTuple(rel, insertTuple, u_sess->catalog_cxt.route, false);
|
||||
|
||||
/* if the partition exists, return partition's oid */
|
||||
if (u_sess->catalog_cxt.route->fileExist) {
|
||||
@ -7132,7 +7132,7 @@ Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL, bool canIgnor
|
||||
Oid partitionid = InvalidOid;
|
||||
|
||||
/* get routing result */
|
||||
partitionRoutingForTuple(rel, tuple, u_sess->catalog_cxt.route);
|
||||
partitionRoutingForTuple(rel, tuple, u_sess->catalog_cxt.route, canIgnore);
|
||||
|
||||
/* if the partition exists, return partition's oid */
|
||||
if (u_sess->catalog_cxt.route->fileExist) {
|
||||
|
||||
@ -2124,11 +2124,12 @@ lreplace:
|
||||
bool row_movement = false;
|
||||
bool need_create_file = false;
|
||||
int seqNum = -1;
|
||||
bool can_ignore = estate->es_plannedstmt->hasIgnore;
|
||||
if (!partKeyUpdate) {
|
||||
row_movement = false;
|
||||
new_partId = oldPartitionOid;
|
||||
} else {
|
||||
partitionRoutingForTuple(result_relation_desc, tuple, u_sess->exec_cxt.route);
|
||||
partitionRoutingForTuple(result_relation_desc, tuple, u_sess->exec_cxt.route, can_ignore);
|
||||
|
||||
if (u_sess->exec_cxt.route->fileExist) {
|
||||
new_partId = u_sess->exec_cxt.route->partitionId;
|
||||
@ -2136,11 +2137,11 @@ lreplace:
|
||||
Partition part = partitionOpen(result_relation_desc, new_partId, RowExclusiveLock);
|
||||
Relation partRel = partitionGetRelation(result_relation_desc, part);
|
||||
|
||||
partitionRoutingForTuple(partRel, tuple, u_sess->exec_cxt.route);
|
||||
partitionRoutingForTuple(partRel, tuple, u_sess->exec_cxt.route, can_ignore);
|
||||
if (u_sess->exec_cxt.route->fileExist) {
|
||||
new_partId = u_sess->exec_cxt.route->partitionId;
|
||||
} else {
|
||||
int level = estate->es_plannedstmt->hasIgnore ? WARNING : ERROR;
|
||||
int level = can_ignore ? WARNING : ERROR;
|
||||
ereport(level, (errmodule(MOD_EXECUTOR),
|
||||
(errcode(ERRCODE_PARTITION_ERROR),
|
||||
errmsg("fail to update partitioned table \"%s\"",
|
||||
@ -2150,7 +2151,7 @@ lreplace:
|
||||
|
||||
releaseDummyRelation(&partRel);
|
||||
partitionClose(result_relation_desc, part, NoLock);
|
||||
if (!u_sess->exec_cxt.route->fileExist && estate->es_plannedstmt->hasIgnore) {
|
||||
if (!u_sess->exec_cxt.route->fileExist && can_ignore) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -2174,7 +2175,7 @@ lreplace:
|
||||
* it can not be a range area
|
||||
*/
|
||||
if (u_sess->exec_cxt.route->partArea != PART_AREA_INTERVAL) {
|
||||
if (epqstate->parentestate->es_plannedstmt->hasIgnore) {
|
||||
if (can_ignore) {
|
||||
ereport(WARNING, (errmsg("fail to update partitioned table \"%s\".new tuple does not "
|
||||
"map to any table partition.",
|
||||
RelationGetRelationName(result_relation_desc))));
|
||||
@ -2235,7 +2236,7 @@ lreplace:
|
||||
/*
|
||||
* check constraints first if SQL has keyword IGNORE
|
||||
*/
|
||||
if (estate->es_plannedstmt && estate->es_plannedstmt->hasIgnore &&
|
||||
if (can_ignore &&
|
||||
!ExecCheckIndexConstraints(slot, estate, fake_relation, partition, &isgpi, bucketid,
|
||||
&conflictInfo, &conflictPartOid, &conflictBucketid)) {
|
||||
ereport(WARNING, (errmsg("duplicate key value violates unique constraint in table \"%s\"",
|
||||
@ -2447,7 +2448,7 @@ lreplace:
|
||||
/*
|
||||
* check constraints first if SQL has keyword IGNORE
|
||||
*/
|
||||
if (estate->es_plannedstmt && estate->es_plannedstmt->hasIgnore &&
|
||||
if (can_ignore &&
|
||||
!ExecCheckIndexConstraints(slot, estate, fake_insert_relation, insert_partition, &isgpi,
|
||||
bucketid, &conflictInfo, &conflictPartOid, &conflictBucketid)) {
|
||||
ereport(WARNING, (errmsg("duplicate key value violates unique constraint in table \"%s\"",
|
||||
|
||||
@ -146,7 +146,7 @@ typedef struct HashPartitionMap {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define partitionRoutingForTuple(rel, tuple, partIdentfier) \
|
||||
#define partitionRoutingForTuple(rel, tuple, partIdentfier, canIgnore) \
|
||||
do { \
|
||||
TupleDesc tuple_desc = NULL; \
|
||||
int2vector *partkey_column = NULL; \
|
||||
@ -169,6 +169,14 @@ typedef struct HashPartitionMap {
|
||||
transformDatum2Const((rel)->rd_att, partkey_column->values[i], column_raw, isnull, &consts[i]); \
|
||||
} \
|
||||
if (PartitionMapIsInterval((rel)->partMap) && values[0]->constisnull) { \
|
||||
if (canIgnore) { \
|
||||
/* treat type as PART_TYPE_RANGE because PART_TYPE_INTERVAL will create a new partition. \
|
||||
* this will be handled by caller and directly return */ \
|
||||
(partIdentfier)->partArea = PART_AREA_RANGE; \
|
||||
(partIdentfier)->fileExist = false; \
|
||||
(partIdentfier)->partitionId = InvalidOid; \
|
||||
break; \
|
||||
} \
|
||||
ereport(ERROR, \
|
||||
(errcode(ERRCODE_INTERNAL_ERROR), errmsg("inserted partition key does not map to any partition"), \
|
||||
errdetail("inserted partition key cannot be NULL for interval-partitioned table"))); \
|
||||
|
||||
@ -304,6 +304,71 @@ select * from t_ignore;
|
||||
3000 | abc
|
||||
(1 row)
|
||||
|
||||
-- test for interval partition table
|
||||
drop table if exists t_interval_partition cascade;
|
||||
NOTICE: table "t_interval_partition" does not exist, skipping
|
||||
create table t_interval_partition
|
||||
(
|
||||
id1 integer primary key,
|
||||
id3 integer,
|
||||
c_3 date
|
||||
)
|
||||
PARTITION BY RANGE (c_3) INTERVAL('1 year')
|
||||
(
|
||||
PARTITION P1 values less than ('2018-03-16 16:27:04'),
|
||||
PARTITION P2 values less than ('2020-03-16 16:27:04'),
|
||||
PARTITION P4 values less than ('2022-03-16 16:27:04')
|
||||
) ENABLE ROW MOVEMENT;
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t_interval_partition_pkey" for table "t_interval_partition"
|
||||
-- test for interval partition table, opfusion: on
|
||||
set enable_partition_opfusion = on;
|
||||
insert into t_interval_partition values (1, 1, null);
|
||||
ERROR: inserted partition key does not map to any partition
|
||||
DETAIL: inserted partition key cannot be NULL for interval-partitioned table
|
||||
insert /*+ ignore_error */ into t_interval_partition values (1, 1, null);
|
||||
WARNING: inserted partition key does not map to any table partition
|
||||
select * from t_interval_partition;
|
||||
id1 | id3 | c_3
|
||||
-----+-----+-----
|
||||
(0 rows)
|
||||
|
||||
insert into t_interval_partition values (1, 1, '2023-02-01 00:00:00');
|
||||
update t_interval_partition set c_3 = null where id1 = 1;
|
||||
ERROR: inserted partition key does not map to any partition
|
||||
DETAIL: inserted partition key cannot be NULL for interval-partitioned table
|
||||
update /*+ ignore_error */ t_interval_partition set c_3 = null where id1 = 1;
|
||||
WARNING: fail to update partitioned table "t_interval_partition".new tuple does not map to any table partition.
|
||||
select * from t_interval_partition;
|
||||
id1 | id3 | c_3
|
||||
-----+-----+------------
|
||||
1 | 1 | 02-01-2023
|
||||
(1 row)
|
||||
|
||||
-- test for interval partition table, opfusion: off
|
||||
delete from t_interval_partition;
|
||||
set enable_partition_opfusion = off;
|
||||
insert into t_interval_partition values (1, 1, null);
|
||||
ERROR: inserted partition key does not map to any partition
|
||||
DETAIL: inserted partition key cannot be NULL for interval-partitioned table
|
||||
insert /*+ ignore_error */ into t_interval_partition values (1, 1, null);
|
||||
WARNING: inserted partition key does not map to any table partition
|
||||
select * from t_interval_partition;
|
||||
id1 | id3 | c_3
|
||||
-----+-----+-----
|
||||
(0 rows)
|
||||
|
||||
insert into t_interval_partition values (1, 1, '2023-02-01 00:00:00');
|
||||
update t_interval_partition set c_3 = null where id1 = 1;
|
||||
ERROR: inserted partition key does not map to any partition
|
||||
DETAIL: inserted partition key cannot be NULL for interval-partitioned table
|
||||
update /*+ ignore_error */ t_interval_partition set c_3 = null where id1 = 1;
|
||||
WARNING: fail to update partitioned table "t_interval_partition".new tuple does not map to any table partition.
|
||||
select * from t_interval_partition;
|
||||
id1 | id3 | c_3
|
||||
-----+-----+------------
|
||||
1 | 1 | 02-01-2023
|
||||
(1 row)
|
||||
|
||||
set enable_opfusion = on;
|
||||
set enable_partition_opfusion = off;
|
||||
drop table t_ignore;
|
||||
|
||||
@ -153,6 +153,42 @@ insert into t_ignore values(3000, 'abc');
|
||||
update /*+ ignore_error */ t_ignore set col1 = 20000 where col1 = 3000;
|
||||
select * from t_ignore;
|
||||
|
||||
-- test for interval partition table
|
||||
drop table if exists t_interval_partition cascade;
|
||||
create table t_interval_partition
|
||||
(
|
||||
id1 integer primary key,
|
||||
id3 integer,
|
||||
c_3 date
|
||||
)
|
||||
PARTITION BY RANGE (c_3) INTERVAL('1 year')
|
||||
(
|
||||
PARTITION P1 values less than ('2018-03-16 16:27:04'),
|
||||
PARTITION P2 values less than ('2020-03-16 16:27:04'),
|
||||
PARTITION P4 values less than ('2022-03-16 16:27:04')
|
||||
) ENABLE ROW MOVEMENT;
|
||||
|
||||
-- test for interval partition table, opfusion: on
|
||||
set enable_partition_opfusion = on;
|
||||
insert into t_interval_partition values (1, 1, null);
|
||||
insert /*+ ignore_error */ into t_interval_partition values (1, 1, null);
|
||||
select * from t_interval_partition;
|
||||
insert into t_interval_partition values (1, 1, '2023-02-01 00:00:00');
|
||||
update t_interval_partition set c_3 = null where id1 = 1;
|
||||
update /*+ ignore_error */ t_interval_partition set c_3 = null where id1 = 1;
|
||||
select * from t_interval_partition;
|
||||
|
||||
-- test for interval partition table, opfusion: off
|
||||
delete from t_interval_partition;
|
||||
set enable_partition_opfusion = off;
|
||||
insert into t_interval_partition values (1, 1, null);
|
||||
insert /*+ ignore_error */ into t_interval_partition values (1, 1, null);
|
||||
select * from t_interval_partition;
|
||||
insert into t_interval_partition values (1, 1, '2023-02-01 00:00:00');
|
||||
update t_interval_partition set c_3 = null where id1 = 1;
|
||||
update /*+ ignore_error */ t_interval_partition set c_3 = null where id1 = 1;
|
||||
select * from t_interval_partition;
|
||||
|
||||
set enable_opfusion = on;
|
||||
set enable_partition_opfusion = off;
|
||||
drop table t_ignore;
|
||||
|
||||
Reference in New Issue
Block a user