issue修复:ignore插入时,若插入值类型与目标类型无转换规则,目标类型的默认零值无法被插入的问题修复

This commit is contained in:
teooooozhang
2022-07-27 10:36:22 +08:00
parent b08bcca779
commit e91ae0c8cc
8 changed files with 196 additions and 33 deletions

View File

@ -1356,6 +1356,7 @@ static Query* transformInsertStmt(ParseState* pstate, InsertStmt* stmt)
qry->commandType = CMD_INSERT;
pstate->p_is_insert = true;
pstate->p_has_ignore = stmt->hasIgnore;
/* set io state for backend status for the thread, we will use it to check user space */
pgstat_set_io_state(IOSTATE_WRITE);
@ -3325,6 +3326,7 @@ static Query* transformUpdateStmt(ParseState* pstate, UpdateStmt* stmt)
qry->commandType = CMD_UPDATE;
pstate->p_is_insert = false;
pstate->p_has_ignore = stmt->hasIgnore;
/* set io state for backend status for the thread, we will use it to check user space */
pgstat_set_io_state(IOSTATE_READ);

View File

@ -58,6 +58,7 @@ ParseState* make_parsestate(ParseState* parentParseState)
pstate->ignoreplus = false;
pstate->p_plusjoin_rte_info = NULL;
pstate->p_rawdefaultlist = NIL;
pstate->p_has_ignore = false;
if (parentParseState != NULL) {
pstate->p_sourcetext = parentParseState->p_sourcetext;

View File

@ -33,6 +33,7 @@
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "utils/typcache.h"
#include "executor/executor.h"
#include "gs_ledger/ledger_utils.h"
static void markTargetListOrigin(ParseState* pstate, TargetEntry* tle, Var* var, int levelsup);
@ -513,17 +514,24 @@ Expr* transformAssignedExpr(ParseState* pstate, Expr* expr, char* colname, int a
colname, format_type_be(attrtype), format_type_be(type_id)),
errhint("You will need to rewrite or cast the expression."),
parser_errposition(pstate, exprLocation(orig_expr))));
} else {
if (!pstate->p_has_ignore) {
ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" is of type %s"
" but expression is of type %s",
colname, format_type_be(attrtype), format_type_be(type_id)),
errhint("You will need to rewrite or cast the expression."),
parser_errposition(pstate, exprLocation(orig_expr))));
}
expr = (Expr*)makeConst(attrtype, attrtypmod, attrcollation, rd->rd_att->attrs[attrno - 1]->attlen,
GetTypeZeroValue(rd->rd_att->attrs[attrno - 1]), false,
rd->rd_att->attrs[attrno - 1]->attbyval);
ereport(WARNING, (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" is of type %s"
" but expression is of type %s. Data truncated automatically.",
colname, format_type_be(attrtype), format_type_be(type_id))));
}
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" is of type %s"
" but expression is of type %s",
colname,
format_type_be(attrtype),
format_type_be(type_id)),
errhint("You will need to rewrite or cast the expression."),
parser_errposition(pstate, exprLocation(orig_expr))));
}
}
}
ELOG_FIELD_NAME_END;

View File

@ -2438,9 +2438,9 @@ void PthreadRwLockInit(pthread_rwlock_t* rwlock, pthread_rwlockattr_t *attr)
}
/*
* Get defaulted value of specific time type
* Get defaulted value of specific type
*/
static Datum GetTimeTypeZeroValue(Form_pg_attribute att_tup)
Datum GetTypeZeroValue(Form_pg_attribute att_tup)
{
Datum result;
switch (att_tup->atttypid) {
@ -2473,21 +2473,10 @@ static Datum GetTimeTypeZeroValue(Form_pg_attribute att_tup)
smalldatetime_in, CStringGetDatum("1970-01-01 08:00:00"), ObjectIdGetDatum(0), Int32GetDatum(-1));
break;
}
default: {
case DATEOID: {
result = timestamp2date(SetEpochTimestamp());
break;
}
}
return result;
}
/*
* Get defaulted value of specific non-time type
*/
static Datum GetNotTimeTypeZeroValue(Form_pg_attribute att_tup)
{
Datum result;
switch (att_tup->atttypid) {
case UUIDOID: {
result = (Datum)DirectFunctionCall3(uuid_in, CStringGetDatum("00000000-0000-0000-0000-000000000000"),
ObjectIdGetDatum(0), Int32GetDatum(-1));
@ -2576,15 +2565,7 @@ Tuple ReplaceTupleNullCol(TupleDesc tupleDesc, TupleTableSlot *slot)
int attrChk;
for (attrChk = 1; attrChk <= natts; attrChk++) {
if (tupleDesc->attrs[attrChk - 1]->attnotnull && tableam_tslot_attisnull(slot, attrChk)) {
bool isTimeType = (tupleDesc->attrs[attrChk - 1]->atttypid == DATEOID ||
tupleDesc->attrs[attrChk - 1]->atttypid == TIMESTAMPOID ||
tupleDesc->attrs[attrChk - 1]->atttypid == TIMESTAMPTZOID ||
tupleDesc->attrs[attrChk - 1]->atttypid == TIMETZOID ||
tupleDesc->attrs[attrChk - 1]->atttypid == INTERVALOID ||
tupleDesc->attrs[attrChk - 1]->atttypid == TINTERVALOID ||
tupleDesc->attrs[attrChk - 1]->atttypid == SMALLDATETIMEOID);
values[attrChk - 1] = isTimeType ? GetTimeTypeZeroValue(tupleDesc->attrs[attrChk - 1])
: GetNotTimeTypeZeroValue(tupleDesc->attrs[attrChk - 1]);
values[attrChk - 1] = GetTypeZeroValue(tupleDesc->attrs[attrChk - 1]);
replaces[attrChk - 1] = true;
}
}

View File

@ -466,6 +466,7 @@ extern void ExecSimpleRelationDelete(EState *estate, EPQState *epqstate, TupleTa
FakeRelationPartition *relAndPart);
extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd);
extern void GetFakeRelAndPart(EState *estate, Relation rel, TupleTableSlot *slot, FakeRelationPartition *relAndPart);
extern Datum GetTypeZeroValue(Form_pg_attribute att_tup);
extern Tuple ReplaceTupleNullCol(TupleDesc tupleDesc, TupleTableSlot* slot);
// AutoMutexLock

View File

@ -189,6 +189,7 @@ struct ParseState {
List *sw_fromClause;
WithClause *origin_with;
bool p_hasStartWith;
bool p_has_ignore; /* whether SQL has ignore hint */
/*
* Optional hook functions for parser callbacks. These are null unless

View File

@ -791,5 +791,123 @@ select * from t_int;
12
(1 row)
-- test for inconvertible type transform.
drop table if exists t_int;
create table t_int(num int);
insert /*+ ignore_error */ into t_int values('2011-8-2'::timestamp);
WARNING: column "num" is of type integer but expression is of type timestamp without time zone. Data truncated automatically.
CONTEXT: referenced column: num
select * from t_int;
num
-----
0
(1 row)
delete from t_int;
drop table if exists t_timestamp;
NOTICE: table "t_timestamp" does not exist, skipping
create table t_timestamp(val timestamp);
insert into t_timestamp values('2011-8-2');
insert /*+ ignore_error */ into t_int select val from t_timestamp;
WARNING: column "num" is of type integer but expression is of type timestamp without time zone. Data truncated automatically.
CONTEXT: referenced column: num
select * from t_int;
num
-----
0
(1 row)
delete from t_int;
insert into t_int values(999);
update /*+ ignore_error */ t_int set num = '2011-8-2'::timestamp;
WARNING: column "num" is of type integer but expression is of type timestamp without time zone. Data truncated automatically.
CONTEXT: referenced column: num
select * from t_int;
num
-----
0
(1 row)
drop table if exists t_multi;
NOTICE: table "t_multi" does not exist, skipping
create table t_multi(c1 int unique, c2 int);
NOTICE: CREATE TABLE / UNIQUE will create implicit index "t_multi_c1_key" for table "t_multi"
insert /*+ ignore_error */ into t_multi values('2011-8-2'::timestamp, 1);
WARNING: column "c1" is of type integer but expression is of type timestamp without time zone. Data truncated automatically.
CONTEXT: referenced column: c1
insert /*+ ignore_error */ into t_multi values(0, 0) on duplicate key update c2 = 2;
select * from t_multi;
c1 | c2
----+----
0 | 2
(1 row)
insert /*+ ignore_error */ into t_multi values('2011-8-2'::timestamp , 3) on duplicate key update c2 = 3;
WARNING: column "c1" is of type integer but expression is of type timestamp without time zone. Data truncated automatically.
CONTEXT: referenced column: c1
select * from t_multi;
c1 | c2
----+----
0 | 3
(1 row)
drop table if exists t_float8;
NOTICE: table "t_float8" does not exist, skipping
create table t_float8(num float8);
insert /*+ ignore_error */ into t_float8 values('2011-8-2'::timestamp);
WARNING: column "num" is of type double precision but expression is of type timestamp without time zone. Data truncated automatically.
CONTEXT: referenced column: num
select * from t_float8;
num
-----
0
(1 row)
delete from t_float8;
insert into t_float8 values(123.999);
update /*+ ignore_error */ t_float8 set num = '2011-8-2'::timestamp;
WARNING: column "num" is of type double precision but expression is of type timestamp without time zone. Data truncated automatically.
CONTEXT: referenced column: num
select * from t_float8;
num
-----
0
(1 row)
drop table if exists t_uuid;
NOTICE: table "t_uuid" does not exist, skipping
create table t_uuid(val uuid);
insert /*+ ignore_error */ into t_uuid values(0);
WARNING: column "val" is of type uuid but expression is of type integer. Data truncated automatically.
CONTEXT: referenced column: val
select * from t_uuid;
val
--------------------------------------
00000000-0000-0000-0000-000000000000
(1 row)
drop table if exists t_date;
NOTICE: table "t_date" does not exist, skipping
create table t_date(val date);
insert /*+ ignore_error */ into t_date values(0);
WARNING: column "val" is of type date but expression is of type integer. Data truncated automatically.
CONTEXT: referenced column: val
select * from t_date;
val
------------
01-01-1970
(1 row)
delete from t_date;
insert into t_date values('2011-8-2');
update /*+ ignore_error */ t_date set val = 0;
WARNING: column "val" is of type date but expression is of type integer. Data truncated automatically.
CONTEXT: referenced column: val
select * from t_date;
val
------------
01-01-1970
(1 row)
\c postgres
drop database if exists sql_ignore_type_transform_test;

View File

@ -342,5 +342,56 @@ create table t_int(num int);
insert /*+ ignore_error */ into t_int values('12a34');
select * from t_int;
-- test for inconvertible type transform.
drop table if exists t_int;
create table t_int(num int);
insert /*+ ignore_error */ into t_int values('2011-8-2'::timestamp);
select * from t_int;
delete from t_int;
drop table if exists t_timestamp;
create table t_timestamp(val timestamp);
insert into t_timestamp values('2011-8-2');
insert /*+ ignore_error */ into t_int select val from t_timestamp;
select * from t_int;
delete from t_int;
insert into t_int values(999);
update /*+ ignore_error */ t_int set num = '2011-8-2'::timestamp;
select * from t_int;
drop table if exists t_multi;
create table t_multi(c1 int unique, c2 int);
insert /*+ ignore_error */ into t_multi values('2011-8-2'::timestamp, 1);
insert /*+ ignore_error */ into t_multi values(0, 0) on duplicate key update c2 = 2;
select * from t_multi;
insert /*+ ignore_error */ into t_multi values('2011-8-2'::timestamp , 3) on duplicate key update c2 = 3;
select * from t_multi;
drop table if exists t_float8;
create table t_float8(num float8);
insert /*+ ignore_error */ into t_float8 values('2011-8-2'::timestamp);
select * from t_float8;
delete from t_float8;
insert into t_float8 values(123.999);
update /*+ ignore_error */ t_float8 set num = '2011-8-2'::timestamp;
select * from t_float8;
drop table if exists t_uuid;
create table t_uuid(val uuid);
insert /*+ ignore_error */ into t_uuid values(0);
select * from t_uuid;
drop table if exists t_date;
create table t_date(val date);
insert /*+ ignore_error */ into t_date values(0);
select * from t_date;
delete from t_date;
insert into t_date values('2011-8-2');
update /*+ ignore_error */ t_date set val = 0;
select * from t_date;
\c postgres
drop database if exists sql_ignore_type_transform_test;