From d0da2c46cad441818681dda8649f3411ec74f1d9 Mon Sep 17 00:00:00 2001 From: zwgiles Date: Mon, 31 Mar 2025 18:59:06 -0700 Subject: [PATCH 01/10] D format IDENTITY constraint --- contrib/shark/expected/identity.out | 292 ++++++++++++++++++ contrib/shark/parallel_schedule | 1 + contrib/shark/sql/identity.sql | 165 ++++++++++ .../shark/src/backend_parser/gram-tsql-decl.y | 1 + .../gram-tsql-nonassoc-ident-tokens | 3 +- .../shark/src/backend_parser/gram-tsql-rule.y | 21 ++ src/common/backend/parser/analyze.cpp | 24 ++ src/common/backend/parser/parse_utilcmd.cpp | 43 ++- .../optimizer/commands/sequence/sequence.cpp | 5 + .../optimizer/commands/tablecmds.cpp | 3 +- src/include/nodes/parsenodes_common.h | 3 +- 11 files changed, 556 insertions(+), 5 deletions(-) create mode 100644 contrib/shark/expected/identity.out create mode 100644 contrib/shark/sql/identity.sql diff --git a/contrib/shark/expected/identity.out b/contrib/shark/expected/identity.out new file mode 100644 index 0000000000..2c97e9268d --- /dev/null +++ b/contrib/shark/expected/identity.out @@ -0,0 +1,292 @@ +CREATE TABLE book(bookId int IDENTITY, bookname NVARCHAR(50), author NVARCHAR(50)); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +INSERT INTO book VALUES(3,'book5','author5'); +select * from book; + bookid | bookname | author +--------+----------+--------- + 1 | book1 | author1 + 2 | book2 | author2 + 3 | book3 | author3 + 4 | book4 | author4 + 3 | book5 | author5 +(5 rows) + +drop table if exists book; +CREATE TABLE book +( + bookId int NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +select * from book; + bookid | bookname | author +--------+----------+--------- + 1 | book1 | author1 + 2 | book2 | author2 +(2 rows) + +drop table if exists book; +CREATE TABLE book +( + bookId int NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +select * from book; + bookid | bookname | author +--------+----------+--------- + 3 | book1 | author1 + 8 | book2 | author2 +(2 rows) + +delete book where bookId=8; +select * from book; + bookid | bookname | author +--------+----------+--------- + 3 | book1 | author1 +(1 row) + +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; + bookid | bookname | author +--------+----------+--------- + 3 | book1 | author1 + 13 | book3 | author3 + 18 | book4 | author4 +(3 rows) + +drop table if exists book; +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +CREATE TABLE book +( + bookId smallint NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +CREATE TABLE book +( + bookId bigint NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +CREATE TABLE book +( + bookId numeric NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +CREATE TABLE book +( + bookId decimal NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +CREATE TABLE book +( + bookname NVARCHAR(50), + author NVARCHAR(50) +); +ALTER TABLE book add bookId int not null primary key identity; +NOTICE: ALTER TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: ALTER TABLE / ADD PRIMARY KEY will create implicit index "book_pkey" for table "book" +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +select * from book; + bookname | author | bookid +----------+---------+-------- + book1 | author1 | 1 + book2 | author2 | 2 +(2 rows) + +delete book where bookId=8; +select * from book; + bookname | author | bookid +----------+---------+-------- + book1 | author1 | 1 + book2 | author2 | 2 +(2 rows) + +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; + bookname | author | bookid +----------+---------+-------- + book1 | author1 | 1 + book2 | author2 | 2 + book3 | author3 | 3 + book4 | author4 | 4 +(4 rows) + +drop table if exists book; +CREATE TABLE book +( + bookId int NOT NULL PRIMARY KEY IDENTITY(100,100), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; + bookid | bookname | author +--------+----------+--------- + 100 | book1 | author1 + 200 | book2 | author2 + 300 | book3 | author3 + 400 | book4 | author4 +(4 rows) + +drop table if exists book; +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(-1,1), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +ERROR: START value (-1) cannot be less than MINVALUE (1) +drop table if exists book; +NOTICE: table "book" does not exist, skipping +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(0,-1), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +ERROR: START value (0) cannot be greater than MAXVALUE (-1) +drop table if exists book; +NOTICE: table "book" does not exist, skipping +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(255,256), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +CREATE TABLE book +( + bookId smallint NOT NULL PRIMARY KEY IDENTITY(32767,32768), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +CREATE TABLE book +( + bookId text NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +drop table if exists book; +C5REATE TABLE book +( + bookId numeric(4,2) NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), + author NVARCHAR(50) +); +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; + bookid | bookname | author +--------+----------+--------- + 1.00 | book1 | author1 + 2.00 | book2 | author2 + 3.00 | book3 | author3 + 4.00 | book4 | author4 +(4 rows) + +drop table if exists book; +CREATE TABLE t_identity(id serial, col int identity(5,10), col2 text) +partition by range(col)( +partition p1 VALUES LESS THAN (10), +partition p2 VALUES LESS THAN (20), +partition p3 VALUES LESS THAN (30), +partition p4 VALUES LESS THAN (MAXVALUE) +); +NOTICE: CREATE TABLE will create implicit sequence "t_identity_id_seq" for serial column "t_identity.id" +NOTICE: CREATE TABLE will create implicit sequence "t_identity_col_seq" for serial column "t_identity.col" +insert into t_identity(col2) values('abc'); +insert into t_identity(col2) values('def'); +insert into t_identity(col2) values('ghi'); +insert into t_identity(col2) values('jkl'); +select * from t_identity partition(p1); + id | col | col2 +----+-----+------ + 1 | 5 | abc +(1 row) + +select * from t_identity partition(p2); + id | col | col2 +----+-----+------ + 2 | 15 | def +(1 row) + +select * from t_identity partition(p3); + id | col | col2 +----+-----+------ + 3 | 25 | ghi +(1 row) + +select * from t_identity partition(p4); + id | col | col2 +----+-----+------ + 4 | 35 | jkl +(1 row) + +drop table t_identity; +CREATE TABLE t_identity(id decimal(12) not null identity(1,1), col text); +NOTICE: CREATE TABLE will create implicit sequence "t_identity_id_seq" for serial column "t_identity.id" +insert into t_identity values('aaa'); +select * from t_identity; + id | col +----+----- + 1 | aaa +(1 row) + +drop table if exists t_identity; + +CREATE TABLE t_identity(id decimal(12,2) not null identity(1,1), col text); +NOTICE: CREATE TABLE will create implicit sequence "t_identity_id_seq" for serial column "t_identity.id" +insert into t_identity values('aaa'); +select * from t_identity; + id | col +------+----- + 1.00 | aaa +(1 row) + +drop table if exists t_identity; diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index 23bb475c99..e892ad30ce 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -4,6 +4,7 @@ test: basetest test: day_test rand_test test: objectproperty test: clustered_index insert_stmt sbr_test +test: identity test: test_ddl_and_dml test: rotate-test-part2 rotate-test-part2_ci test: functions diff --git a/contrib/shark/sql/identity.sql b/contrib/shark/sql/identity.sql new file mode 100644 index 0000000000..b648c9e6c1 --- /dev/null +++ b/contrib/shark/sql/identity.sql @@ -0,0 +1,165 @@ +CREATE TABLE book(bookId int IDENTITY, bookname NVARCHAR(50), author NVARCHAR(50)); +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +INSERT INTO book VALUES(3,'book5','author5'); +select * from book; +drop table if exists book; + +CREATE TABLE book +( + bookId int NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), + author NVARCHAR(50) +); +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +select * from book; +drop table if exists book; + +CREATE TABLE book +( + bookId int NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +select * from book; +delete book where bookId=8; +select * from book; +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; +drop table if exists book; + +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId smallint NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId bigint NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId numeric NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId decimal NOT NULL PRIMARY KEY IDENTITY(3,5), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookname NVARCHAR(50), + author NVARCHAR(50) +); +ALTER TABLE book add bookId int not null primary key identity; +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +select * from book; +delete book where bookId=8; +select * from book; +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; +drop table if exists book; + +CREATE TABLE book +( + bookId int NOT NULL PRIMARY KEY IDENTITY(100,100), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; +drop table if exists book; + + +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(-1,1), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(0,-1), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(255,256), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId smallint NOT NULL PRIMARY KEY IDENTITY(32767,32768), + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId text NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), + author NVARCHAR(50) +); +drop table if exists book; +CREATE TABLE book +( + bookId numeric(4,2) NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), + author NVARCHAR(50) +); +INSERT INTO book VALUES('book1','author1'),('book2','author2'); +INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); +select * from book; +drop table if exists book; + +CREATE TABLE t_identity(id serial, col int identity(5,10), col2 text) +partition by range(col)( +partition p1 VALUES LESS THAN (10), +partition p2 VALUES LESS THAN (20), +partition p3 VALUES LESS THAN (30), +partition p4 VALUES LESS THAN (MAXVALUE) +); +insert into t_identity(col2) values('abc'); +insert into t_identity(col2) values('def'); +insert into t_identity(col2) values('ghi'); +insert into t_identity(col2) values('jkl'); +select * from t_identity partition(p1); +select * from t_identity partition(p2); +select * from t_identity partition(p3); +select * from t_identity partition(p4); +drop table t_identity; + +CREATE TABLE t_identity(id decimal(12) not null identity(1,1), col text); +insert into t_identity values('aaa'); +select * from t_identity; +drop table if exists t_identity; + +CREATE TABLE t_identity(id decimal(12,2) not null identity(1,1), col text); +insert into t_identity values('aaa'); +select * from t_identity; +drop table if exists t_identity; + diff --git a/contrib/shark/src/backend_parser/gram-tsql-decl.y b/contrib/shark/src/backend_parser/gram-tsql-decl.y index b284521b6a..9f25bddedd 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-decl.y +++ b/contrib/shark/src/backend_parser/gram-tsql-decl.y @@ -8,5 +8,6 @@ %type TSQL_computed_column %type tsql_top_clause tsql_select_top_value %type tsql_opt_ties tsql_opt_percent +%type identity_seed_increment %type DirectColLabel %type direct_label_keyword diff --git a/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens b/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens index 8bb73b236e..056d456ff1 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens +++ b/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens @@ -1 +1,2 @@ -TSQL_PERSISTED /* these tokens can follow b_expr. To resolve ambiguity, we need to assign the same priority with IDENT. please see the comment in gram.y for details */ \ No newline at end of file +IDENTITY_P +TSQL_PERSISTED /* these tokens can follow b_expr. To resolve ambiguity, we need to assign the same priority with IDENT. please see the comment in gram.y for details */ diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index 61f3343307..34570f6ad3 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -462,6 +462,27 @@ tsql_CreateProcedureStmt: } ; +ColConstraintElem: IDENTITY_P identity_seed_increment + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_IDENTITY; + n->generated_when = ATTRIBUTE_IDENTITY_ALWAYS; + n->options = $2; + n->location = @1; + $$ = (Node *)n; + } + ; + +identity_seed_increment: + '(' NumericOnly ',' NumericOnly ')' + { + $$ = list_make2(makeDefElem("start", (Node *)$2), makeDefElem("increment",(Node *)$4)); + } + | /* EMPTY */ + { + $$ = list_make2(makeDefElem("start", (Node *)makeInteger(1)), makeDefElem("increment", (Node *)makeInteger(1))); + } + ; rotate_clause: ROTATE '(' func_application_list rotate_for_clause rotate_in_clause ')' alias_clause %prec ROTATE { diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 97b18c8a09..2f5d00b66d 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -152,6 +152,7 @@ static bool checkAllowedTableCombination(ParseState* pstate); static bool ContainSubLinkWalker(Node* node, void* context); static bool ContainSubLink(Node* clause); #endif /* ENABLE_MULTIPLE_NODES */ +extern Oid pg_get_serial_sequence_oid(text* tablename, text* columnname); #ifndef ENABLE_MULTIPLE_NODES static const char* NOKEYUPDATE_KEYSHARE_ERRMSG = "/NO KEY UPDATE/KEY SHARE"; @@ -2701,6 +2702,29 @@ List* transformInsertRow(ParseState* pstate, List* exprlist, List* stmtcols, Lis parser_errposition(pstate, exprLocation((Node*)list_nth(icolumns, list_length(exprlist)))))); } + if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT + && list_length(exprlist) < list_length(icolumns)) { + Relation targetrel = (Relation)linitial(pstate->p_target_relation); + FormData_pg_attribute* attr = targetrel->rd_att->attrs; + int numcol = RelationGetNumberOfAttributes(targetrel); + + forboth (icols, icolumns, attnos, attrnos) { + ResTarget* col = NULL; + text *relname = NULL; + text *colname = NULL; + col = (ResTarget*)lfirst(icols); + + relname = cstring_to_text(RelationGetRelationName(targetrel)); + colname = cstring_to_text(col->name); + + if (pg_get_serial_sequence_oid(relname, colname) != InvalidOid) { + icolumns = list_delete_cell2(icolumns, icols); + attrnos = list_delete_cell2(attrnos, attnos); + } + pfree_ext(relname); + pfree_ext(colname); + } + } /* * Prepare columns for assignment to target table. */ diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 7667b668f9..cc536ab7a7 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -1011,7 +1011,7 @@ static bool DropSetOwnedByTable(CreateStmtContext* cxt, char *colname) * create a sequence owned by table, need to add record to pg_depend. * used in CREATE TABLE and CREATE TABLE ... LIKE */ -static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, bool is_autoinc) +static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, bool is_autoinc, bool for_identity=false, bool enable_null=false, List *seqoptions=NULL) { Oid snamespaceid; char* snamespace = NULL; @@ -1025,7 +1025,11 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo AlterSeqStmt* altseqstmt = NULL; List* attnamelist = NIL; Constraint* constraint = NULL; + Oid typeOid = InvalidOid; + if (column->typname) { + typeOid = typenameTypeId(NULL, column->typname); + } /* * Determine namespace and name to use for the sequence. * @@ -1061,13 +1065,21 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo */ seqstmt = makeNode(CreateSeqStmt); seqstmt->sequence = makeRangeVar(snamespace, sname, -1); - seqstmt->options = is_autoinc ? GetAutoIncSeqOptions(cxt) : NULL; + seqstmt->options = seqoptions; seqstmt->is_autoinc = is_autoinc; #ifdef PGXC seqstmt->is_serial = true; #endif seqstmt->is_large = large; + if (for_identity) { + seqstmt->options = lcons(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, -1)),seqstmt->options); + } else if (!large) { + seqstmt->options = list_make1(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, -1))); + } else { + seqstmt->options = is_autoinc? GetAutoIncSeqOptions(cxt) : NULL; + } + /* Assign UUID for create sequence */ seqstmt->uuid = INVALIDSEQUUID; #ifdef ENABLE_MUTIPLE_NODES @@ -1395,6 +1407,7 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD bool saw_generated = false; Constraint* constraint = NULL; ListCell* clist = NULL; + bool saw_identity = false; foreach (clist, column->constraints) { constraint = (Constraint*)lfirst(clist); @@ -1442,6 +1455,32 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD saw_default = true; break; + case CONSTR_IDENTITY: + { + bool large = (column->typname->typeOid == NUMERICOID); + + if (cxt->ofType) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("identity columns are not supported on typed tables"))); + } + if (saw_identity) { + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple identity specifications for column \"%s\" of table \"%s\"", + column->colname, cxt->relation->relname), + parser_errposition(cxt->pstate, constraint->location))); + } + if (saw_default) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Defaults cannot be created on columns with an IDENTITY attribute. Table '%s', column '%s'", + cxt->relation->relname,column->colname), + parser_errposition(cxt->pstate, constraint->location))); + + createSeqOwnedByTable(cxt,column,preCheck,large,false,true,false,constraint->options); + + saw_identity = true; + break; + } + case CONSTR_GENERATED: if (cxt->ofType) { ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index edb1a5f49b..475e4c3baf 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -2119,6 +2119,7 @@ enum { DEF_IDX_MIN_VALUE, DEF_IDX_CACHE_VALUE, DEF_IDX_IS_CYCLED, + DEF_IDX_TYPE_ID, DEF_IDX_NUM }; @@ -2168,6 +2169,10 @@ static void PreProcessSequenceOptions( } else if (strcmp(defel->defname, "owned_by") == 0) { CheckDuplicateDef(*owned_by); *owned_by = defGetQualifiedName(defel); + } else if (strcmp(defel->defname, "as") == 0) { + CheckDuplicateDef(elms[DEF_IDX_TYPE_ID]); + elms[DEF_IDX_TYPE_ID] = defel; + *need_seq_rewrite = true; } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("option \"%s\" not recognized", defel->defname))); } diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index dc3d75c1de..95870bfe8b 100755 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -13596,7 +13596,8 @@ static ObjectAddress ATExecAddColumn(List** wqueue, AlteredTableInfo* tab, Relat if (colDef->is_not_null) { ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, true, is_addloc); } - } else if (contain_specified_function((Node*)defval, NEXTVALFUNCOID)) { + } else if (contain_specified_function((Node*)defval, NEXTVALFUNCOID) + && u_sess->attr.attr_sql.sql_compatibility != D_FORMAT) { /* We don't support alter table add column which default with nextval expression. */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index f89e1d564c..38cf773c38 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -1445,7 +1445,8 @@ typedef enum ConstrType { /* types of constraints */ CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_GENERATED, - CONSTR_AUTO_INCREMENT + CONSTR_AUTO_INCREMENT, + CONSTR_IDENTITY } ConstrType; typedef struct Constraint { -- Gitee From d14301f7892f9b1ec580860b1fd3f5f3e05bf94e Mon Sep 17 00:00:00 2001 From: zwgiles Date: Mon, 14 Apr 2025 01:08:55 -0700 Subject: [PATCH 02/10] update the identity --- src/common/backend/parser/analyze.cpp | 23 ---- src/common/backend/parser/parse_target.cpp | 19 +++ src/common/backend/parser/parse_utilcmd.cpp | 119 +++++++++++++++- .../optimizer/commands/sequence/sequence.cpp | 128 ++++++++++++++++-- src/include/commands/sequence.h | 3 + src/include/pg_config_manual.h | 6 + 6 files changed, 257 insertions(+), 41 deletions(-) diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 2f5d00b66d..0fae6a9884 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -2702,29 +2702,6 @@ List* transformInsertRow(ParseState* pstate, List* exprlist, List* stmtcols, Lis parser_errposition(pstate, exprLocation((Node*)list_nth(icolumns, list_length(exprlist)))))); } - if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT - && list_length(exprlist) < list_length(icolumns)) { - Relation targetrel = (Relation)linitial(pstate->p_target_relation); - FormData_pg_attribute* attr = targetrel->rd_att->attrs; - int numcol = RelationGetNumberOfAttributes(targetrel); - - forboth (icols, icolumns, attnos, attrnos) { - ResTarget* col = NULL; - text *relname = NULL; - text *colname = NULL; - col = (ResTarget*)lfirst(icols); - - relname = cstring_to_text(RelationGetRelationName(targetrel)); - colname = cstring_to_text(col->name); - - if (pg_get_serial_sequence_oid(relname, colname) != InvalidOid) { - icolumns = list_delete_cell2(icolumns, icols); - attrnos = list_delete_cell2(attrnos, attnos); - } - pfree_ext(relname); - pfree_ext(colname); - } - } /* * Prepare columns for assignment to target table. */ diff --git a/src/common/backend/parser/parse_target.cpp b/src/common/backend/parser/parse_target.cpp index c2c41a50bc..d4694d9145 100644 --- a/src/common/backend/parser/parse_target.cpp +++ b/src/common/backend/parser/parse_target.cpp @@ -922,6 +922,25 @@ List* checkInsertTargets(ParseState* pstate, List* cols, List** attrnos) if (is_blockchain_rel && strcmp(col->name, "hash") == 0) { continue; } + /* skip the identity default value in D format */ + if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT) { + FunctionCallInfoData funcinfo; + Datum re_seq; + char* sequenceName = NULL; + + InitFunctionCallInfoData(funcinfo, NULL, 2, InvalidOid, NULL, NULL); + + funcinfo.arg[0] = CStringGetTextDatum(RelationGetRelationName(targetrel)); + funcinfo.arg[1] = CStringGetTextDatum(col->name); + + re_seq = pg_get_serial_sequence(&funcinfo); + if (re_seq != NULL) { + sequenceName = TextDatumGetCString(re_seq); + if (sequenceName != NULL && strstr(sequenceName, "_seq_identity") != NULL) + continue; + } + } + col->indirection = NIL; col->val = NULL; col->location = -1; diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index cc536ab7a7..f4efccb3bc 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -156,6 +156,8 @@ static void transformColumnType(CreateStmtContext* cxt, ColumnDef* column); static void setSchemaName(char* context_schema, char** stmt_schema_name); static void TransformTempAutoIncrement(ColumnDef* column, CreateStmt* stmt); static int128 TransformAutoIncStart(CreateStmt* stmt); +static void identity_type_dmod(ColumnDef* column); +static int identity_only(ColumnDef* column); /* * @hdfs @@ -589,6 +591,7 @@ Oid *namespaceid, bool isFirstNode) * Run through each primary element in the table creation clause. Separate * column defs from constraints, and do preliminary analysis. */ + int count = 0; foreach (elements, stmt->tableElts) { TableLikeClause* tbl_like_clause = NULL; TransformTableType transformType = TRANSFORM_INVALID; @@ -604,6 +607,14 @@ Oid *namespaceid, bool isFirstNode) (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("\"hash\" column is reserved for system in ledger schema."))); } + + count += identity_only((ColumnDef*)element); + if (count > 1) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("table can have only one identity column"))); + } + transformColumnDefinition(&cxt, (ColumnDef*)element, !isFirstNode && preCheck); if (((ColumnDef *)element)->clientLogicColumnRef != NULL) { @@ -1030,6 +1041,49 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo if (column->typname) { typeOid = typenameTypeId(NULL, column->typname); } + + if (for_identity && nodeTag(cxt->node) == T_AlterTableStmt) { + Relation attRelation; + Relation rel; + SysScanDesc scan; + ScanKeyData key[1]; + HeapTuple tuple; + Form_pg_attribute attrForm; + char* columnName; + FunctionCallInfoData funcinfo; + char* sequenceName; + Datum re_seq; + + InitFunctionCallInfoData(funcinfo, NULL, 2, InvalidOid, NULL, NULL); + attRelation = heap_open(AttributeRelationId, AccessShareLock); + + rel = heap_openrv(cxt->relation, AccessShareLock); + + ScanKeyInit(&key[0], Anum_pg_attribute_attrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel))); + + scan = systable_beginscan(attRelation, AttributeRelidNumIndexId, true, NULL, 1, key); + while ((tuple = systable_getnext(scan)) != NULL) { + attrForm = (Form_pg_attribute) GETSTRUCT(tuple); + columnName = NameStr(attrForm->attname); + funcinfo.arg[0] = CStringGetTextDatum(cxt->relation->relname); + funcinfo.arg[1] = CStringGetTextDatum(columnName); + re_seq = pg_get_serial_sequence(&funcinfo); + if (re_seq != NULL) + sequenceName = TextDatumGetCString(re_seq); + else + continue; + + if (sequenceName != NULL && strstr(sequenceName, "_seq_identity") != NULL) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple identity specifications for column \"%s\" of table \"%s\"", + columnName, cxt->relation->relname), + parser_errposition(cxt->pstate, -1))); + } + systable_endscan(scan); + heap_close(rel, AccessShareLock); + heap_close(attRelation, AccessShareLock); + } + /* * Determine namespace and name to use for the sequence. * @@ -1048,7 +1102,12 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid); } snamespace = get_namespace_name(snamespaceid); - sname = ChooseRelationName(cxt->relation->relname, column->colname, "seq", strlen("seq"), snamespaceid); + + if (for_identity) { + sname = ChooseRelationName(cxt->relation->relname, column->colname, "seq_identity", strlen("seq_identity"), snamespaceid); + } else { + sname = ChooseRelationName(cxt->relation->relname, column->colname, "seq", strlen("seq"), snamespaceid); + } if (!preCheck || IS_SINGLE_NODE) ereport(NOTICE, @@ -1073,7 +1132,13 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo seqstmt->is_large = large; if (for_identity) { - seqstmt->options = lcons(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, -1)),seqstmt->options); + int typemod = 0; + if (column->typname->typmods != NULL ) { + typemod = intVal(&((A_Const*)lfirst(list_head(column->typname->typmods)))->val); + seqstmt->options = lcons(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, typemod)),seqstmt->options); + } else { + seqstmt->options = lcons(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, -1)),seqstmt->options); + } } else if (!large) { seqstmt->options = list_make1(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, -1))); } else { @@ -1457,7 +1522,7 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD case CONSTR_IDENTITY: { - bool large = (column->typname->typeOid == NUMERICOID); + bool large = typenameTypeId(NULL, column->typname) == NUMERICOID; if (cxt->ofType) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -1475,9 +1540,10 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD cxt->relation->relname,column->colname), parser_errposition(cxt->pstate, constraint->location))); - createSeqOwnedByTable(cxt,column,preCheck,large,false,true,false,constraint->options); - + identity_type_dmod(column); + createSeqOwnedByTable(cxt, column, preCheck, large, false, true, false, constraint->options); saw_identity = true; + column->is_not_null = true; break; } @@ -8620,3 +8686,46 @@ static void TransformModifyColumndef(CreateStmtContext* cxt, AlterTableCmd* cmd) cxt->blist = lappend(cxt->blist, rename); } } + +static int identity_only(ColumnDef* column) +{ + ListCell* clist = NULL; + Constraint* constraint = NULL; + int result = 0; + foreach (clist, column->constraints) { + constraint = (Constraint*)lfirst(clist); + + switch (constraint->contype) { + case CONSTR_IDENTITY: + result+=1; + break; + default: + break; + } + } + return result; +} + +/* + * Get the column type which is constrained by identity in D mode. + * Check the type is expected or not, and report error for invalid type. + */ +static void identity_type_dmod(ColumnDef* column) +{ + int s = 0; + Oid newtypid = typenameTypeId(NULL, column->typname); + if (newtypid == NUMERICOID) { + if (column->typname->typmods != NULL && list_length(column->typname->typmods) == 2) { + s = intVal(&((A_Const*)lfirst(list_tail(column->typname->typmods)))->val); + } + } + if (newtypid != INT2OID && + newtypid != INT4OID && + newtypid != INT8OID && + newtypid != INT1OID && + newtypid != INT16OID && + (newtypid != NUMERICOID || (newtypid == NUMERICOID && s != 0))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Identity column '%s' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to be nonnullable.", column->colname))); +} diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index 475e4c3baf..d2df3c0a47 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -77,10 +77,10 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt); #ifdef PGXC template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* is_restart, bool* need_seq_rewrite); + bool* is_restart, bool* need_seq_rewrite, bool is_identity); #else static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* need_seq_rewrite); + bool* need_seq_rewrite, bool is_identity); #endif template static void do_setval(Oid relid, int128 next, bool iscalled, bool skip_perm_check = false); @@ -913,22 +913,23 @@ static ObjectAddress DefineSequence(CreateSeqStmt* seq) (errcode(ERRCODE_DATA_CORRUPTED), errmsg("Invaild UUID for CREATE SEQUENCE %s.", seq->sequence->relname))); #endif + bool is_identity = strstr(seq->sequence->relname, "_seq_identity") != NULL; /* Check and set all option values */ #ifdef PGXC if (large) { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &is_restart, &need_seq_rewrite); + &is_restart, &need_seq_rewrite, is_identity); } else { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &is_restart, &need_seq_rewrite); + &is_restart, &need_seq_rewrite, is_identity); } #else if (large) { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &need_seq_rewrite); + &need_seq_rewrite, is_identity); } else { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &need_seq_rewrite); + &need_seq_rewrite, is_identity); } #endif /* @@ -1221,6 +1222,7 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) #endif bool need_seq_rewrite = false; ObjectAddress address; + bool is_identity = false; /* Open and lock sequence. */ relid = RangeVarGetRelid(stmt->sequence, ShareRowExclusiveLock, stmt->missing_ok); @@ -1265,13 +1267,15 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) newm = (T_Form)GETSTRUCT(tuple); + is_identity = strstr(RelationGetRelationName(seqrel), "_seq_identity") != NULL; + /* Check and set new values */ #ifdef PGXC init_params(stmt->options, false, isUseLocalSeq, newm, &owned_by, - &is_restart, &need_seq_rewrite); + &is_restart, &need_seq_rewrite, is_identity); #else init_params(stmt->options, false, isUseLocalSeq, newm, &owned_by, - &need_seq_rewrite); + &need_seq_rewrite, is_identity); #endif #ifdef PGXC /* PGXC_COORD */ /* @@ -2179,6 +2183,33 @@ static void PreProcessSequenceOptions( } } +template +static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, bool is_identity, Oid &type_id, int &type_mods) +{ + if (is_identity) { + if (elm != NULL) { + Oid newtypid = typenameTypeId(NULL, defGetTypeName(elm)); + type_id = newtypid; + + if (nodeTag(elm->arg) == T_TypeName) { + TypeName* typname = (TypeName*)elm->arg; + type_mods = typname->typemod; + } + + if (type_mods > DMODE_MAX_PRECISION) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Specified column precision %d is greater than the maximum precision of %d.", type_mods, DMODE_MAX_PRECISION))); + } + } + } else { + if (!large) + type_id = INT8OID; + else + type_id = INT16OID; + } +} + template static void ProcessSequenceOptIncrementBy(DefElem* elm, T_Form newm, bool isInit) { @@ -2306,6 +2337,56 @@ static void CrossCheckMinMax(T_Int min, T_Int max) } } +template +static bool check_seed_increment_value_min_max(T_Int value, T_Int min_value, T_Int max_value) +{ + if (value < min_value || value > max_value) { + return false; + } + return true; +} + +template +static void ProcessSequenceOptMaxMin(DefElem* elm, T_Form newm, bool isInit, Oid type_id, int type_mods) +{ + if (elm != NULL && elm->arg) { + AssignInt(&(newm->max_value), defGetInt(elm)); + newm->log_cnt = 0; + } else if (isInit || elm != NULL) { + /* ascending seq */ + if (large) { + if (type_mods == -1) + type_mods = DMODE_DEFAULT_PRECISION; + + int128 maxDecimalNum = 9; + int128 minDecimalNum = -1; + for (int i=1; i(&(newm->max_value), maxDecimalNum); + AssignInt(&(newm->min_value), minDecimalNum); + } else { + if (type_id == INT1OID) { + AssignInt(&(newm->max_value), SEQ_MAXVALUE_8); + AssignInt(&(newm->min_value), SEQ_MINVALUE_8); + } else if (type_id == INT2OID) { + AssignInt(&(newm->max_value), SEQ_MAXVALUE_16); + AssignInt(&(newm->min_value), SEQ_MINVALUE_16); + } else if (type_id == INT4OID) { + AssignInt(&(newm->max_value), SEQ_MAXVALUE_32); + AssignInt(&(newm->min_value), SEQ_MINVALUE_32); + } else { + AssignInt(&(newm->max_value), SEQ_MAXVALUE); + AssignInt(&(newm->min_value), SEQ_MINVALUE); + } + } + newm->log_cnt = 0; + } +} + /* * init_params: process the options list of CREATE or ALTER SEQUENCE, * and store the values into appropriate fields of *new. Also set @@ -2325,15 +2406,16 @@ static void CrossCheckMinMax(T_Int min, T_Int max) #ifdef PGXC template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* is_restart, bool* need_seq_rewrite) + bool* is_restart, bool* need_seq_rewrite, bool is_identity) #else template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* need_seq_rewrite) + bool* need_seq_rewrite, bool is_identity) #endif { T_Form newm = (T_Form)newm_p; DefElem* elms[DEF_IDX_NUM] = {0}; + Oid type_id = InvalidOid; #ifdef PGXC *is_restart = false; @@ -2351,10 +2433,17 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne newm->log_cnt = 0; } + int type_mods = -1; + + ProcessSequenceOptAsType(elms[DEF_IDX_TYPE_ID], newm, isInit, is_identity, type_id, type_mods); ProcessSequenceOptIncrementBy(elms[DEF_IDX_INCREMENT_BY], newm, isInit); ProcessSequenceOptCycle(elms[DEF_IDX_IS_CYCLED], newm, isInit); - ProcessSequenceOptMax(elms[DEF_IDX_MAX_VALUE], newm, isInit); - ProcessSequenceOptMin(elms[DEF_IDX_MIN_VALUE], newm, isInit); + if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT && is_identity) { + ProcessSequenceOptMaxMin(elms[DEF_IDX_MIN_VALUE], newm, isInit, type_id, type_mods); + } else { + ProcessSequenceOptMax(elms[DEF_IDX_MAX_VALUE], newm, isInit); + ProcessSequenceOptMin(elms[DEF_IDX_MIN_VALUE], newm, isInit); + } /* crosscheck min/max */ CrossCheckMinMax(newm->min_value, newm->max_value); @@ -2362,7 +2451,20 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne ProcessSequenceOptStartWith(elms[DEF_IDX_START_VALUE], newm, isInit); /* crosscheck START */ - CheckValueMinMax(newm->start_value, newm->min_value, newm->max_value, true); + if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT && is_identity) { + if (!check_seed_increment_value_min_max(newm->start_value, newm->min_value, newm->max_value)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Identity column contains invalid SEED."))); + } + if (!check_seed_increment_value_min_max(newm->increment_by, newm->min_value, newm->max_value)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Identity column contains invalid INCREMENT."))); + } + } else { + CheckValueMinMax(newm->start_value, newm->min_value, newm->max_value, true); + } ProcessSequenceOptReStartWith( elms[DEF_IDX_RESTART_VALUE], newm, isInit, is_restart, isUseLocalSeq); diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 66d8655f76..98b4a3a468 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -89,6 +89,9 @@ typedef FormData_pg_large_sequence* Form_pg_large_sequence; #define GS_NUM_OF_BUCKETS 1024 +#define DMODE_MAX_PRECISION 38 +#define DMODE_DEFAULT_PRECISION 18 + /* * The "special area" of a old version sequence's buffer page looks like this. */ diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 21dbff2281..911bb2c46a 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -57,6 +57,12 @@ */ #define SEQ_MAXVALUE INT64CONST(0x7FFFFFFFFFFFFFFF) #define SEQ_MINVALUE (-SEQ_MAXVALUE) +#define SEQ_MAXVALUE_32 0x7FFFFFFF +#define SEQ_MINVALUE_32 (-SEQ_MAXVALUE_32 - 1) +#define SEQ_MAXVALUE_16 0x7FFF +#define SEQ_MINVALUE_16 (-SEQ_MAXVALUE_16 - 1) +#define SEQ_MAXVALUE_8 0xFF +#define SEQ_MINVALUE_8 0x00 #define LARGE_SEQ_MAXVALUE (int128)(((uint128)1 << 127) - 1) #define LARGE_SEQ_MINVALUE (-INT128_MAX - 1) -- Gitee From 0936880dcdef7164a81c5ca49f52fa7c5fd855de Mon Sep 17 00:00:00 2001 From: zwgiles Date: Mon, 14 Apr 2025 03:17:20 -0700 Subject: [PATCH 03/10] fix regression test --- contrib/shark/expected/identity.out | 78 ++++++++++++----------------- contrib/shark/sql/identity.sql | 7 --- 2 files changed, 31 insertions(+), 54 deletions(-) diff --git a/contrib/shark/expected/identity.out b/contrib/shark/expected/identity.out index 2c97e9268d..5510427bf5 100644 --- a/contrib/shark/expected/identity.out +++ b/contrib/shark/expected/identity.out @@ -1,8 +1,11 @@ CREATE TABLE book(bookId int IDENTITY, bookname NVARCHAR(50), author NVARCHAR(50)); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" INSERT INTO book VALUES('book1','author1'),('book2','author2'); INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); INSERT INTO book VALUES(3,'book5','author5'); +ERROR: INSERT has more expressions than target columns +LINE 1: INSERT INTO book VALUES(3,'book5','author5'); + ^ select * from book; bookid | bookname | author --------+----------+--------- @@ -10,8 +13,7 @@ select * from book; 2 | book2 | author2 3 | book3 | author3 4 | book4 | author4 - 3 | book5 | author5 -(5 rows) +(4 rows) drop table if exists book; CREATE TABLE book @@ -20,7 +22,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" INSERT INTO book VALUES('book1','author1'),('book2','author2'); select * from book; @@ -37,7 +39,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" INSERT INTO book VALUES('book1','author1'),('book2','author2'); select * from book; @@ -70,7 +72,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" drop table if exists book; CREATE TABLE book @@ -79,7 +81,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" drop table if exists book; CREATE TABLE book @@ -88,7 +90,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" drop table if exists book; CREATE TABLE book @@ -97,7 +99,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" drop table if exists book; CREATE TABLE book @@ -106,7 +108,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" drop table if exists book; CREATE TABLE book @@ -115,7 +117,7 @@ CREATE TABLE book author NVARCHAR(50) ); ALTER TABLE book add bookId int not null primary key identity; -NOTICE: ALTER TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: ALTER TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: ALTER TABLE / ADD PRIMARY KEY will create implicit index "book_pkey" for table "book" INSERT INTO book VALUES('book1','author1'),('book2','author2'); select * from book; @@ -150,7 +152,7 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" INSERT INTO book VALUES('book1','author1'),('book2','author2'); INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); @@ -167,11 +169,11 @@ drop table if exists book; CREATE TABLE book ( bookId tinyint NOT NULL PRIMARY KEY IDENTITY(-1,1), - bookname NVARCHAR(50), + bookname NVARCHAR(50), author NVARCHAR(50) ); NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -ERROR: START value (-1) cannot be less than MINVALUE (1) +ERROR: Identity column contains invalid SEED drop table if exists book; NOTICE: table "book" does not exist, skipping CREATE TABLE book @@ -181,7 +183,7 @@ CREATE TABLE book author NVARCHAR(50) ); NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -ERROR: START value (0) cannot be greater than MAXVALUE (-1) +ERROR: Identity column contains invalid INCREMENT drop table if exists book; NOTICE: table "book" does not exist, skipping CREATE TABLE book @@ -190,47 +192,36 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" +ERROR: Identity column contains invalid INCREMENT drop table if exists book; +NOTICE: table "book" does not exist, skipping CREATE TABLE book ( bookId smallint NOT NULL PRIMARY KEY IDENTITY(32767,32768), bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" +ERROR: Identity column contains invalid INCREMENT drop table if exists book; +NOTICE: table "book" does not exist, skipping CREATE TABLE book ( bookId text NOT NULL PRIMARY KEY IDENTITY, bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" +ERROR: Identity column 'bookid' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to be nonnullable. drop table if exists book; -C5REATE TABLE book +NOTICE: table "book" does not exist, skipping +CREATE TABLE book ( bookId numeric(4,2) NOT NULL PRIMARY KEY IDENTITY, bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "book_pkey" for table "book" -INSERT INTO book VALUES('book1','author1'),('book2','author2'); -INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); -select * from book; - bookid | bookname | author ---------+----------+--------- - 1.00 | book1 | author1 - 2.00 | book2 | author2 - 3.00 | book3 | author3 - 4.00 | book4 | author4 -(4 rows) - -drop table if exists book; +ERROR: Identity column 'bookid' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to be nonnullable. CREATE TABLE t_identity(id serial, col int identity(5,10), col2 text) partition by range(col)( partition p1 VALUES LESS THAN (10), @@ -239,7 +230,7 @@ partition p3 VALUES LESS THAN (30), partition p4 VALUES LESS THAN (MAXVALUE) ); NOTICE: CREATE TABLE will create implicit sequence "t_identity_id_seq" for serial column "t_identity.id" -NOTICE: CREATE TABLE will create implicit sequence "t_identity_col_seq" for serial column "t_identity.col" +NOTICE: CREATE TABLE will create implicit sequence "t_identity_col_seq_identity" for serial column "t_identity.col" insert into t_identity(col2) values('abc'); insert into t_identity(col2) values('def'); insert into t_identity(col2) values('ghi'); @@ -270,7 +261,7 @@ select * from t_identity partition(p4); drop table t_identity; CREATE TABLE t_identity(id decimal(12) not null identity(1,1), col text); -NOTICE: CREATE TABLE will create implicit sequence "t_identity_id_seq" for serial column "t_identity.id" +NOTICE: CREATE TABLE will create implicit sequence "t_identity_id_seq_identity" for serial column "t_identity.id" insert into t_identity values('aaa'); select * from t_identity; id | col @@ -281,12 +272,5 @@ select * from t_identity; drop table if exists t_identity; CREATE TABLE t_identity(id decimal(12,2) not null identity(1,1), col text); -NOTICE: CREATE TABLE will create implicit sequence "t_identity_id_seq" for serial column "t_identity.id" -insert into t_identity values('aaa'); -select * from t_identity; - id | col -------+----- - 1.00 | aaa -(1 row) - -drop table if exists t_identity; +ERROR: Identity column 'bookid' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to b +e nonnullable diff --git a/contrib/shark/sql/identity.sql b/contrib/shark/sql/identity.sql index b648c9e6c1..08eb1f37f1 100644 --- a/contrib/shark/sql/identity.sql +++ b/contrib/shark/sql/identity.sql @@ -131,10 +131,6 @@ CREATE TABLE book bookname NVARCHAR(50), author NVARCHAR(50) ); -INSERT INTO book VALUES('book1','author1'),('book2','author2'); -INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); -select * from book; -drop table if exists book; CREATE TABLE t_identity(id serial, col int identity(5,10), col2 text) partition by range(col)( @@ -159,7 +155,4 @@ select * from t_identity; drop table if exists t_identity; CREATE TABLE t_identity(id decimal(12,2) not null identity(1,1), col text); -insert into t_identity values('aaa'); -select * from t_identity; -drop table if exists t_identity; -- Gitee From c94ddc6ab08ed0ba8ccc712e4a537799cfc7d16b Mon Sep 17 00:00:00 2001 From: zwgiles Date: Tue, 15 Apr 2025 19:24:20 -0700 Subject: [PATCH 04/10] update expected file --- contrib/shark/expected/identity.out | 44 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/contrib/shark/expected/identity.out b/contrib/shark/expected/identity.out index 5510427bf5..dbb417815a 100644 --- a/contrib/shark/expected/identity.out +++ b/contrib/shark/expected/identity.out @@ -121,7 +121,7 @@ NOTICE: ALTER TABLE will create implicit sequence "book_bookid_seq_identity" fo NOTICE: ALTER TABLE / ADD PRIMARY KEY will create implicit index "book_pkey" for table "book" INSERT INTO book VALUES('book1','author1'),('book2','author2'); select * from book; - bookname | author | bookid + bookname | author | bookid ----------+---------+-------- book1 | author1 | 1 book2 | author2 | 2 @@ -129,7 +129,7 @@ select * from book; delete book where bookId=8; select * from book; - bookname | author | bookid + bookname | author | bookid ----------+---------+-------- book1 | author1 | 1 book2 | author2 | 2 @@ -137,7 +137,7 @@ select * from book; INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); select * from book; - bookname | author | bookid + bookname | author | bookid ----------+---------+-------- book1 | author1 | 1 book2 | author2 | 2 @@ -168,48 +168,48 @@ select * from book; drop table if exists book; CREATE TABLE book ( - bookId tinyint NOT NULL PRIMARY KEY IDENTITY(-1,1), + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(-1,1), bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -ERROR: Identity column contains invalid SEED +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" +ERROR: Identity column contains invalid SEED. drop table if exists book; NOTICE: table "book" does not exist, skipping CREATE TABLE book ( - bookId tinyint NOT NULL PRIMARY KEY IDENTITY(0,-1), - bookname NVARCHAR(50), + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(0,-1), + bookname NVARCHAR(50), author NVARCHAR(50) ); -NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq" for serial column "book.bookid" -ERROR: Identity column contains invalid INCREMENT +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" +ERROR: Identity column contains invalid INCREMENT. drop table if exists book; NOTICE: table "book" does not exist, skipping CREATE TABLE book ( - bookId tinyint NOT NULL PRIMARY KEY IDENTITY(255,256), - bookname NVARCHAR(50), + bookId tinyint NOT NULL PRIMARY KEY IDENTITY(255,256), + bookname NVARCHAR(50), author NVARCHAR(50) ); NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" -ERROR: Identity column contains invalid INCREMENT +ERROR: Identity column contains invalid INCREMENT. drop table if exists book; NOTICE: table "book" does not exist, skipping CREATE TABLE book ( - bookId smallint NOT NULL PRIMARY KEY IDENTITY(32767,32768), - bookname NVARCHAR(50), + bookId smallint NOT NULL PRIMARY KEY IDENTITY(32767,32768), + bookname NVARCHAR(50), author NVARCHAR(50) ); NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" -ERROR: Identity column contains invalid INCREMENT +ERROR: Identity column contains invalid INCREMENT. drop table if exists book; NOTICE: table "book" does not exist, skipping CREATE TABLE book ( - bookId text NOT NULL PRIMARY KEY IDENTITY, - bookname NVARCHAR(50), + bookId text NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), author NVARCHAR(50) ); ERROR: Identity column 'bookid' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to be nonnullable. @@ -217,8 +217,8 @@ drop table if exists book; NOTICE: table "book" does not exist, skipping CREATE TABLE book ( - bookId numeric(4,2) NOT NULL PRIMARY KEY IDENTITY, - bookname NVARCHAR(50), + bookId numeric(4,2) NOT NULL PRIMARY KEY IDENTITY, + bookname NVARCHAR(50), author NVARCHAR(50) ); ERROR: Identity column 'bookid' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to be nonnullable. @@ -270,7 +270,5 @@ select * from t_identity; (1 row) drop table if exists t_identity; - CREATE TABLE t_identity(id decimal(12,2) not null identity(1,1), col text); -ERROR: Identity column 'bookid' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to b -e nonnullable +ERROR: Identity column 'id' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to be nonnullable. -- Gitee From 28624e290e1c2fc549f167de2b75ab58c1c61be1 Mon Sep 17 00:00:00 2001 From: zwgiles Date: Thu, 24 Apr 2025 19:42:03 -0700 Subject: [PATCH 05/10] fix codecheck problem --- src/common/backend/parser/analyze.cpp | 2 +- src/common/backend/parser/parse_target.cpp | 6 ++- src/common/backend/parser/parse_utilcmd.cpp | 44 +++++++++---------- .../optimizer/commands/sequence/sequence.cpp | 10 +++-- src/include/commands/sequence.h | 1 + 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 0fae6a9884..8f369404c4 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -87,6 +87,7 @@ #include "utils/typcache.h" #include "commands/explain.h" #include "commands/sec_rls_cmds.h" +#include "commands/sequence.h" #include "streaming/streaming_catalog.h" #include "instruments/instr_unique_sql.h" #include "streaming/init.h" @@ -152,7 +153,6 @@ static bool checkAllowedTableCombination(ParseState* pstate); static bool ContainSubLinkWalker(Node* node, void* context); static bool ContainSubLink(Node* clause); #endif /* ENABLE_MULTIPLE_NODES */ -extern Oid pg_get_serial_sequence_oid(text* tablename, text* columnname); #ifndef ENABLE_MULTIPLE_NODES static const char* NOKEYUPDATE_KEYSHARE_ERRMSG = "/NO KEY UPDATE/KEY SHARE"; diff --git a/src/common/backend/parser/parse_target.cpp b/src/common/backend/parser/parse_target.cpp index d4694d9145..8418f4f756 100644 --- a/src/common/backend/parser/parse_target.cpp +++ b/src/common/backend/parser/parse_target.cpp @@ -927,8 +927,9 @@ List* checkInsertTargets(ParseState* pstate, List* cols, List** attrnos) FunctionCallInfoData funcinfo; Datum re_seq; char* sequenceName = NULL; + int nargs = 2; - InitFunctionCallInfoData(funcinfo, NULL, 2, InvalidOid, NULL, NULL); + InitFunctionCallInfoData(funcinfo, NULL, nargs, InvalidOid, NULL, NULL); funcinfo.arg[0] = CStringGetTextDatum(RelationGetRelationName(targetrel)); funcinfo.arg[1] = CStringGetTextDatum(col->name); @@ -936,8 +937,9 @@ List* checkInsertTargets(ParseState* pstate, List* cols, List** attrnos) re_seq = pg_get_serial_sequence(&funcinfo); if (re_seq != NULL) { sequenceName = TextDatumGetCString(re_seq); - if (sequenceName != NULL && strstr(sequenceName, "_seq_identity") != NULL) + if (sequenceName != NULL && strstr(sequenceName, "_seq_identity") != NULL) { continue; + } } } diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index f4efccb3bc..7b52ef8d95 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -611,7 +611,7 @@ Oid *namespaceid, bool isFirstNode) count += identity_only((ColumnDef*)element); if (count > 1) { ereport(ERROR, - (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("table can have only one identity column"))); } @@ -1022,7 +1022,7 @@ static bool DropSetOwnedByTable(CreateStmtContext* cxt, char *colname) * create a sequence owned by table, need to add record to pg_depend. * used in CREATE TABLE and CREATE TABLE ... LIKE */ -static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, bool is_autoinc, bool for_identity=false, bool enable_null=false, List *seqoptions=NULL) +static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, bool is_autoinc, bool for_identity = false, bool enable_null = false, List *seqoptions = nullptr) { Oid snamespaceid; char* snamespace = NULL; @@ -1068,10 +1068,11 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo funcinfo.arg[0] = CStringGetTextDatum(cxt->relation->relname); funcinfo.arg[1] = CStringGetTextDatum(columnName); re_seq = pg_get_serial_sequence(&funcinfo); - if (re_seq != NULL) + if (re_seq != NULL) { sequenceName = TextDatumGetCString(re_seq); - else + } else { continue; + } if (sequenceName != NULL && strstr(sequenceName, "_seq_identity") != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -1133,14 +1134,14 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo if (for_identity) { int typemod = 0; - if (column->typname->typmods != NULL ) { + if (column->typname->typmods != NULL) { typemod = intVal(&((A_Const*)lfirst(list_head(column->typname->typmods)))->val); - seqstmt->options = lcons(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, typemod)),seqstmt->options); + seqstmt->options = lcons(makeDefElem("as", (Node *)makeTypeNameFromOid(typeOid, typemod)), seqstmt->options); } else { - seqstmt->options = lcons(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, -1)),seqstmt->options); + seqstmt->options = lcons(makeDefElem("as", (Node *)makeTypeNameFromOid(typeOid, -1)), seqstmt->options); } } else if (!large) { - seqstmt->options = list_make1(makeDefElem("as",(Node *)makeTypeNameFromOid(typeOid, -1))); + seqstmt->options = list_make1(makeDefElem("as", (Node *)makeTypeNameFromOid(typeOid, -1))); } else { seqstmt->options = is_autoinc? GetAutoIncSeqOptions(cxt) : NULL; } @@ -1525,23 +1526,23 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD bool large = typenameTypeId(NULL, column->typname) == NUMERICOID; if (cxt->ofType) { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("identity columns are not supported on typed tables"))); } if (saw_identity) { - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple identity specifications for column \"%s\" of table \"%s\"", column->colname, cxt->relation->relname), parser_errposition(cxt->pstate, constraint->location))); } if (saw_default) - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Defaults cannot be created on columns with an IDENTITY attribute. Table '%s', column '%s'", - cxt->relation->relname,column->colname), + cxt->relation->relname, column->colname), parser_errposition(cxt->pstate, constraint->location))); - identity_type_dmod(column); - createSeqOwnedByTable(cxt, column, preCheck, large, false, true, false, constraint->options); + identity_type_dmod(column); + createSeqOwnedByTable(cxt, column, preCheck, large, false, true, false, constraint->options); saw_identity = true; column->is_not_null = true; break; @@ -8695,12 +8696,8 @@ static int identity_only(ColumnDef* column) foreach (clist, column->constraints) { constraint = (Constraint*)lfirst(clist); - switch (constraint->contype) { - case CONSTR_IDENTITY: - result+=1; - break; - default: - break; + if (constraint->contype == CONSTR_IDENTITY) { + result += 1; } } return result; @@ -8714,11 +8711,12 @@ static void identity_type_dmod(ColumnDef* column) { int s = 0; Oid newtypid = typenameTypeId(NULL, column->typname); - if (newtypid == NUMERICOID) { - if (column->typname->typmods != NULL && list_length(column->typname->typmods) == 2) { + if (newtypid == NUMERICOID && + column->typname->typmods != NULL && + list_length(column->typname->typmods) == 2) { s = intVal(&((A_Const*)lfirst(list_tail(column->typname->typmods)))->val); - } } + if (newtypid != INT2OID && newtypid != INT4OID && newtypid != INT8OID && diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index d2df3c0a47..4ccc7e088f 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -2201,7 +2201,7 @@ static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, boo (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Specified column precision %d is greater than the maximum precision of %d.", type_mods, DMODE_MAX_PRECISION))); } - } + } } else { if (!large) type_id = INT8OID; @@ -2360,8 +2360,10 @@ static void ProcessSequenceOptMaxMin(DefElem* elm, T_Form newm, bool isInit, Oid int128 maxDecimalNum = 9; int128 minDecimalNum = -1; - for (int i=1; i(&(newm->max_value), SEQ_MAXVALUE); AssignInt(&(newm->min_value), SEQ_MINVALUE); - } + } } newm->log_cnt = 0; } diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 98b4a3a468..e7875d1c41 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -265,5 +265,6 @@ extern SeqTable GetSessSeqElm(Oid relid); extern char* GetGlobalSeqNameForUpdate(Relation seqrel, char** dbname, char** schemaname); extern uint32 RelidGetHash(Oid seq_relid); extern SeqTable GetGlobalSeqElm(Oid relid, GlobalSeqInfoHashBucket* bucket); +extern Oid pg_get_serial_sequence_oid(text* tablename, text* columnname); #endif /* SEQUENCE_H */ -- Gitee From e473a9e78195dd134c4fba4c6b2892a66b058d2f Mon Sep 17 00:00:00 2001 From: zwgiles Date: Thu, 24 Apr 2025 21:29:11 -0700 Subject: [PATCH 06/10] fix viarable problem --- src/common/backend/parser/parse_utilcmd.cpp | 29 ++++----- .../optimizer/commands/sequence/sequence.cpp | 62 +++++++++---------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 7b52ef8d95..654f9e74c4 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -1022,7 +1022,8 @@ static bool DropSetOwnedByTable(CreateStmtContext* cxt, char *colname) * create a sequence owned by table, need to add record to pg_depend. * used in CREATE TABLE and CREATE TABLE ... LIKE */ -static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, bool is_autoinc, bool for_identity = false, bool enable_null = false, List *seqoptions = nullptr) +static +void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, bool isAutoinc, bool forIdentity = false, List *seqOptions = nullptr) { Oid snamespaceid; char* snamespace = NULL; @@ -1042,7 +1043,7 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo typeOid = typenameTypeId(NULL, column->typname); } - if (for_identity && nodeTag(cxt->node) == T_AlterTableStmt) { + if (forIdentity && nodeTag(cxt->node) == T_AlterTableStmt) { Relation attRelation; Relation rel; SysScanDesc scan; @@ -1104,7 +1105,7 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo } snamespace = get_namespace_name(snamespaceid); - if (for_identity) { + if (forIdentity) { sname = ChooseRelationName(cxt->relation->relname, column->colname, "seq_identity", strlen("seq_identity"), snamespaceid); } else { sname = ChooseRelationName(cxt->relation->relname, column->colname, "seq", strlen("seq"), snamespaceid); @@ -1125,14 +1126,14 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo */ seqstmt = makeNode(CreateSeqStmt); seqstmt->sequence = makeRangeVar(snamespace, sname, -1); - seqstmt->options = seqoptions; - seqstmt->is_autoinc = is_autoinc; + seqstmt->options = seqOptions; + seqstmt->is_autoinc = isAutoinc; #ifdef PGXC seqstmt->is_serial = true; #endif seqstmt->is_large = large; - if (for_identity) { + if (forIdentity) { int typemod = 0; if (column->typname->typmods != NULL) { typemod = intVal(&((A_Const*)lfirst(list_head(column->typname->typmods)))->val); @@ -1143,7 +1144,7 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo } else if (!large) { seqstmt->options = list_make1(makeDefElem("as", (Node *)makeTypeNameFromOid(typeOid, -1))); } else { - seqstmt->options = is_autoinc? GetAutoIncSeqOptions(cxt) : NULL; + seqstmt->options = isAutoinc? GetAutoIncSeqOptions(cxt) : NULL; } /* Assign UUID for create sequence */ @@ -1190,7 +1191,7 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo attnamelist = list_make3(makeString(snamespace), makeString(cxt->relation->relname), makeString(column->colname)); altseqstmt->options = list_make1(makeDefElem("owned_by", (Node*)attnamelist)); altseqstmt->is_large = large; - altseqstmt->is_autoinc = is_autoinc; + altseqstmt->is_autoinc = isAutoinc; cxt->alist = lappend(cxt->alist, altseqstmt); @@ -1227,7 +1228,7 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo constraint = makeNode(Constraint); constraint->contype = CONSTR_DEFAULT; constraint->location = -1; - if (is_autoinc) { + if (isAutoinc) { autoincnode = makeNode(AutoIncrement); autoincnode->expr = (Node*)funccallnode; constraint->raw_expr = (Node*)autoincnode; @@ -1238,7 +1239,7 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo column->constraints = lappend(column->constraints, constraint); column->raw_default = constraint->raw_expr; - if (!is_autoinc) { + if (!isAutoinc) { constraint = makeNode(Constraint); constraint->contype = CONSTR_NOTNULL; constraint->location = -1; @@ -1473,7 +1474,7 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD bool saw_generated = false; Constraint* constraint = NULL; ListCell* clist = NULL; - bool saw_identity = false; + bool sawIdentity = false; foreach (clist, column->constraints) { constraint = (Constraint*)lfirst(clist); @@ -1529,7 +1530,7 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("identity columns are not supported on typed tables"))); } - if (saw_identity) { + if (sawIdentity) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple identity specifications for column \"%s\" of table \"%s\"", column->colname, cxt->relation->relname), @@ -1542,8 +1543,8 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD parser_errposition(cxt->pstate, constraint->location))); identity_type_dmod(column); - createSeqOwnedByTable(cxt, column, preCheck, large, false, true, false, constraint->options); - saw_identity = true; + createSeqOwnedByTable(cxt, column, preCheck, large, false, true, constraint->options); + sawIdentity = true; column->is_not_null = true; break; } diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index 4ccc7e088f..a374e24015 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -77,10 +77,10 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt); #ifdef PGXC template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* is_restart, bool* need_seq_rewrite, bool is_identity); + bool* is_restart, bool* needSeqRewrite, bool isIdentity); #else static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* need_seq_rewrite, bool is_identity); + bool* needSeqRewrite, bool isIdentity); #endif template static void do_setval(Oid relid, int128 next, bool iscalled, bool skip_perm_check = false); @@ -913,23 +913,23 @@ static ObjectAddress DefineSequence(CreateSeqStmt* seq) (errcode(ERRCODE_DATA_CORRUPTED), errmsg("Invaild UUID for CREATE SEQUENCE %s.", seq->sequence->relname))); #endif - bool is_identity = strstr(seq->sequence->relname, "_seq_identity") != NULL; + bool isIdentity = strstr(seq->sequence->relname, "_seq_identity") != NULL; /* Check and set all option values */ #ifdef PGXC if (large) { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &is_restart, &need_seq_rewrite, is_identity); + &is_restart, &need_seq_rewrite, isIdentity); } else { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &is_restart, &need_seq_rewrite, is_identity); + &is_restart, &need_seq_rewrite, isIdentity); } #else if (large) { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &need_seq_rewrite, is_identity); + &need_seq_rewrite, isIdentity); } else { init_params(seq->options, true, isUseLocalSeq, &newm, &owned_by, - &need_seq_rewrite, is_identity); + &need_seq_rewrite, isIdentity); } #endif /* @@ -1222,7 +1222,7 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) #endif bool need_seq_rewrite = false; ObjectAddress address; - bool is_identity = false; + bool isIdentity = false; /* Open and lock sequence. */ relid = RangeVarGetRelid(stmt->sequence, ShareRowExclusiveLock, stmt->missing_ok); @@ -1267,15 +1267,15 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) newm = (T_Form)GETSTRUCT(tuple); - is_identity = strstr(RelationGetRelationName(seqrel), "_seq_identity") != NULL; + isIdentity = strstr(RelationGetRelationName(seqrel), "_seq_identity") != NULL; /* Check and set new values */ #ifdef PGXC init_params(stmt->options, false, isUseLocalSeq, newm, &owned_by, - &is_restart, &need_seq_rewrite, is_identity); + &is_restart, &need_seq_rewrite, isIdentity); #else init_params(stmt->options, false, isUseLocalSeq, newm, &owned_by, - &need_seq_rewrite, is_identity); + &need_seq_rewrite, isIdentity); #endif #ifdef PGXC /* PGXC_COORD */ /* @@ -2184,22 +2184,22 @@ static void PreProcessSequenceOptions( } template -static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, bool is_identity, Oid &type_id, int &type_mods) +static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, bool isIdentity, Oid &type_id, int &typeMods) { - if (is_identity) { + if (isIdentity) { if (elm != NULL) { Oid newtypid = typenameTypeId(NULL, defGetTypeName(elm)); type_id = newtypid; if (nodeTag(elm->arg) == T_TypeName) { TypeName* typname = (TypeName*)elm->arg; - type_mods = typname->typemod; + typeMods = typname->typemod; } - if (type_mods > DMODE_MAX_PRECISION) { + if (typeMods > DMODE_MAX_PRECISION) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Specified column precision %d is greater than the maximum precision of %d.", type_mods, DMODE_MAX_PRECISION))); + errmsg("Specified column precision %d is greater than the maximum precision of %d.", typeMods, DMODE_MAX_PRECISION))); } } } else { @@ -2338,7 +2338,7 @@ static void CrossCheckMinMax(T_Int min, T_Int max) } template -static bool check_seed_increment_value_min_max(T_Int value, T_Int min_value, T_Int max_value) +static bool CheckSeedIncrementValueMinMax(T_Int value, T_Int min_value, T_Int max_value) { if (value < min_value || value > max_value) { return false; @@ -2347,7 +2347,7 @@ static bool check_seed_increment_value_min_max(T_Int value, T_Int min_value, T_I } template -static void ProcessSequenceOptMaxMin(DefElem* elm, T_Form newm, bool isInit, Oid type_id, int type_mods) +static void ProcessSequenceOptMaxMin(DefElem* elm, T_Form newm, bool isInit, Oid type_id, int typeMods) { if (elm != NULL && elm->arg) { AssignInt(&(newm->max_value), defGetInt(elm)); @@ -2355,14 +2355,14 @@ static void ProcessSequenceOptMaxMin(DefElem* elm, T_Form newm, bool isInit, Oid } else if (isInit || elm != NULL) { /* ascending seq */ if (large) { - if (type_mods == -1) - type_mods = DMODE_DEFAULT_PRECISION; + if (typeMods == -1) + typeMods = DMODE_DEFAULT_PRECISION; int128 maxDecimalNum = 9; int128 minDecimalNum = -1; int maxSigDigit = 9; int base = 10; - for (int i = 1; i < type_mods; i++) { + for (int i = 1; i < typeMods; i++) { maxDecimalNum = maxDecimalNum * base + maxSigDigit; } @@ -2408,11 +2408,11 @@ static void ProcessSequenceOptMaxMin(DefElem* elm, T_Form newm, bool isInit, Oid #ifdef PGXC template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* is_restart, bool* need_seq_rewrite, bool is_identity) + bool* is_restart, bool* needSeqRewrite, bool isIdentity) #else template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* need_seq_rewrite, bool is_identity) + bool* needSeqRewrite, bool isIdentity) #endif { T_Form newm = (T_Form)newm_p; @@ -2425,7 +2425,7 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne *owned_by = NIL; - PreProcessSequenceOptions(options, elms, owned_by, need_seq_rewrite, isInit); + PreProcessSequenceOptions(options, elms, owned_by, needSeqRewrite, isInit); /* * We must reset log_cnt when isInit or when changing any parameters @@ -2435,13 +2435,13 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne newm->log_cnt = 0; } - int type_mods = -1; + int typeMods = -1; - ProcessSequenceOptAsType(elms[DEF_IDX_TYPE_ID], newm, isInit, is_identity, type_id, type_mods); + ProcessSequenceOptAsType(elms[DEF_IDX_TYPE_ID], newm, isInit, isIdentity, type_id, typeMods); ProcessSequenceOptIncrementBy(elms[DEF_IDX_INCREMENT_BY], newm, isInit); ProcessSequenceOptCycle(elms[DEF_IDX_IS_CYCLED], newm, isInit); - if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT && is_identity) { - ProcessSequenceOptMaxMin(elms[DEF_IDX_MIN_VALUE], newm, isInit, type_id, type_mods); + if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT && isIdentity) { + ProcessSequenceOptMaxMin(elms[DEF_IDX_MIN_VALUE], newm, isInit, type_id, typeMods); } else { ProcessSequenceOptMax(elms[DEF_IDX_MAX_VALUE], newm, isInit); ProcessSequenceOptMin(elms[DEF_IDX_MIN_VALUE], newm, isInit); @@ -2453,13 +2453,13 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne ProcessSequenceOptStartWith(elms[DEF_IDX_START_VALUE], newm, isInit); /* crosscheck START */ - if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT && is_identity) { - if (!check_seed_increment_value_min_max(newm->start_value, newm->min_value, newm->max_value)) { + if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT && isIdentity) { + if (!CheckSeedIncrementValueMinMax(newm->start_value, newm->min_value, newm->max_value)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Identity column contains invalid SEED."))); } - if (!check_seed_increment_value_min_max(newm->increment_by, newm->min_value, newm->max_value)) { + if (!CheckSeedIncrementValueMinMax(newm->increment_by, newm->min_value, newm->max_value)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Identity column contains invalid INCREMENT."))); -- Gitee From 6114c3270be52cb982f30d68f3db800ea7efeb62 Mon Sep 17 00:00:00 2001 From: zwgiles Date: Thu, 24 Apr 2025 23:04:08 -0700 Subject: [PATCH 07/10] fix code check --- src/common/backend/parser/parse_utilcmd.cpp | 4 ++-- src/gausskernel/optimizer/commands/sequence/sequence.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 654f9e74c4..6a72bdc9d6 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -1022,8 +1022,8 @@ static bool DropSetOwnedByTable(CreateStmtContext* cxt, char *colname) * create a sequence owned by table, need to add record to pg_depend. * used in CREATE TABLE and CREATE TABLE ... LIKE */ -static -void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, bool isAutoinc, bool forIdentity = false, List *seqOptions = nullptr) +static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, +bool isAutoinc, bool forIdentity = false, List *seqOptions = nullptr) { Oid snamespaceid; char* snamespace = NULL; diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index a374e24015..62f3a187b0 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -2184,7 +2184,8 @@ static void PreProcessSequenceOptions( } template -static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, bool isIdentity, Oid &type_id, int &typeMods) +static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, +bool isIdentity, Oid &type_id, int &typeMods) { if (isIdentity) { if (elm != NULL) { @@ -2199,7 +2200,8 @@ static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, boo if (typeMods > DMODE_MAX_PRECISION) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Specified column precision %d is greater than the maximum precision of %d.", typeMods, DMODE_MAX_PRECISION))); + errmsg("Specified column precision %d is greater than the maximum precision of %d.", + typeMods, DMODE_MAX_PRECISION))); } } } else { -- Gitee From c16882217cc694c38cee43491ea8931171d89bd1 Mon Sep 17 00:00:00 2001 From: zwgiles Date: Thu, 24 Apr 2025 23:33:36 -0700 Subject: [PATCH 08/10] fix code check --- src/common/backend/parser/parse_utilcmd.cpp | 4 ++-- src/gausskernel/optimizer/commands/sequence/sequence.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 6a72bdc9d6..5f854503cf 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -1022,8 +1022,8 @@ static bool DropSetOwnedByTable(CreateStmtContext* cxt, char *colname) * create a sequence owned by table, need to add record to pg_depend. * used in CREATE TABLE and CREATE TABLE ... LIKE */ -static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, -bool isAutoinc, bool forIdentity = false, List *seqOptions = nullptr) +static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, bool preCheck, bool large, + bool isAutoinc, bool forIdentity = false, List *seqOptions = nullptr) { Oid snamespaceid; char* snamespace = NULL; diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index 62f3a187b0..7f21de9e1d 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -2184,8 +2184,8 @@ static void PreProcessSequenceOptions( } template -static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, -bool isIdentity, Oid &type_id, int &typeMods) +static void ProcessSequenceOptAsType(DefElem* elm, T_Form newm, bool isInit, + bool isIdentity, Oid &type_id, int &typeMods) { if (isIdentity) { if (elm != NULL) { @@ -2200,8 +2200,8 @@ bool isIdentity, Oid &type_id, int &typeMods) if (typeMods > DMODE_MAX_PRECISION) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Specified column precision %d is greater than the maximum precision of %d.", - typeMods, DMODE_MAX_PRECISION))); + errmsg("Specified column precision %d is greater than the maximum precision of %d.", + typeMods, DMODE_MAX_PRECISION))); } } } else { -- Gitee From 6ab7c28de517c27d91d48d02de5a2a7b934a1c3e Mon Sep 17 00:00:00 2001 From: zwgiles Date: Sun, 27 Apr 2025 08:39:51 -0700 Subject: [PATCH 09/10] fix comment --- contrib/shark/expected/identity.out | 9 ++++++++ contrib/shark/sql/identity.sql | 5 +++++ src/common/backend/parser/parse_target.cpp | 3 ++- src/common/backend/parser/parse_utilcmd.cpp | 4 ++-- .../optimizer/commands/sequence/sequence.cpp | 22 +++++++++++++++++-- src/include/commands/sequence.h | 1 + 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/contrib/shark/expected/identity.out b/contrib/shark/expected/identity.out index dbb417815a..dcaeff8016 100644 --- a/contrib/shark/expected/identity.out +++ b/contrib/shark/expected/identity.out @@ -15,7 +15,12 @@ select * from book; 4 | book4 | author4 (4 rows) +ALTER table book add column id int identity; +ERROR: multiple identity specifications for column "bookid" of table "book" drop table if exists book; +CREATE TABLE book(id int identity, bookId int IDENTITY, bookname NVARCHAR(50), author NVARCHAR(50)); +NOTICE: CREATE TABLE will create implicit sequence "book_id_seq_identity" for serial column "book.id" +ERROR: table can only have one identity column CREATE TABLE book ( bookId int NOT NULL PRIMARY KEY IDENTITY, @@ -222,6 +227,10 @@ CREATE TABLE book author NVARCHAR(50) ); ERROR: Identity column 'bookid' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, unencrypted, and constrained to be nonnullable. +CREATE TABLE book(id serial, bookId int identity default 5, bookname char(20)); +NOTICE: CREATE TABLE will create implicit sequence "book_id_seq" for serial column "book.id" +NOTICE: CREATE TABLE will create implicit sequence "book_bookid_seq_identity" for serial column "book.bookid" +ERROR: multiple default values specified for column "bookid" of table "book" CREATE TABLE t_identity(id serial, col int identity(5,10), col2 text) partition by range(col)( partition p1 VALUES LESS THAN (10), diff --git a/contrib/shark/sql/identity.sql b/contrib/shark/sql/identity.sql index 08eb1f37f1..77e785e9ee 100644 --- a/contrib/shark/sql/identity.sql +++ b/contrib/shark/sql/identity.sql @@ -3,8 +3,11 @@ INSERT INTO book VALUES('book1','author1'),('book2','author2'); INSERT INTO book(bookname,author) VALUES('book3','author3'),('book4','author4'); INSERT INTO book VALUES(3,'book5','author5'); select * from book; +ALTER table book add column id int identity; drop table if exists book; +CREATE TABLE book(id int identity, bookId int IDENTITY, bookname NVARCHAR(50), author NVARCHAR(50)); + CREATE TABLE book ( bookId int NOT NULL PRIMARY KEY IDENTITY, @@ -132,6 +135,8 @@ CREATE TABLE book author NVARCHAR(50) ); +CREATE TABLE book(id serial, bookId int identity default 5, bookname char(20)); + CREATE TABLE t_identity(id serial, col int identity(5,10), col2 text) partition by range(col)( partition p1 VALUES LESS THAN (10), diff --git a/src/common/backend/parser/parse_target.cpp b/src/common/backend/parser/parse_target.cpp index 8418f4f756..bf81989a3f 100644 --- a/src/common/backend/parser/parse_target.cpp +++ b/src/common/backend/parser/parse_target.cpp @@ -39,6 +39,7 @@ #include "gs_ledger/ledger_utils.h" #include "mb/pg_wchar.h" #include "parser/parse_utilcmd.h" +#include "commands/sequence.h" static void markTargetListOrigin(ParseState* pstate, TargetEntry* tle, Var* var, int levelsup); static Node* transformAssignmentIndirection(ParseState* pstate, Node* basenode, const char* targetName, @@ -937,7 +938,7 @@ List* checkInsertTargets(ParseState* pstate, List* cols, List** attrnos) re_seq = pg_get_serial_sequence(&funcinfo); if (re_seq != NULL) { sequenceName = TextDatumGetCString(re_seq); - if (sequenceName != NULL && strstr(sequenceName, "_seq_identity") != NULL) { + if (sequenceName != NULL && StrEndWith(sequenceName, "_seq_identity")) { continue; } } diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 5f854503cf..344e9118f1 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -612,7 +612,7 @@ Oid *namespaceid, bool isFirstNode) if (count > 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("table can have only one identity column"))); + errmsg("table can only have one identity column"))); } transformColumnDefinition(&cxt, (ColumnDef*)element, !isFirstNode && preCheck); @@ -1075,7 +1075,7 @@ static void createSeqOwnedByTable(CreateStmtContext* cxt, ColumnDef* column, boo continue; } - if (sequenceName != NULL && strstr(sequenceName, "_seq_identity") != NULL) + if (sequenceName != NULL && StrEndWith(sequenceName, "_seq_identity")) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple identity specifications for column \"%s\" of table \"%s\"", columnName, cxt->relation->relname), diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index 7f21de9e1d..cc084e4547 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -913,7 +913,7 @@ static ObjectAddress DefineSequence(CreateSeqStmt* seq) (errcode(ERRCODE_DATA_CORRUPTED), errmsg("Invaild UUID for CREATE SEQUENCE %s.", seq->sequence->relname))); #endif - bool isIdentity = strstr(seq->sequence->relname, "_seq_identity") != NULL; + bool isIdentity = StrEndWith(seq->sequence->relname, "_seq_identity"); /* Check and set all option values */ #ifdef PGXC if (large) { @@ -1267,7 +1267,7 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) newm = (T_Form)GETSTRUCT(tuple); - isIdentity = strstr(RelationGetRelationName(seqrel), "_seq_identity") != NULL; + isIdentity = StrEndWith(RelationGetRelationName(seqrel), "_seq_identity"); /* Check and set new values */ #ifdef PGXC @@ -3438,3 +3438,21 @@ int64 get_and_reset_last_value(text* txt, int64 new_value, bool need_reseed) return last_value; } + +bool StrEndWith(const char *str, const char *suffix) +{ + int str_len = strlen(str); + int suffix_len = strlen(suffix); + + if (str_len < suffix_len) { + return false; + } + + for (int i = 0; i < suffix_len; i++) { + if (str[str_len - 1 - i] != suffix[suffix_len - 1 - i]) { + return false; + } + } + + return true; +} diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index e7875d1c41..6682184ab0 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -266,5 +266,6 @@ extern char* GetGlobalSeqNameForUpdate(Relation seqrel, char** dbname, char** sc extern uint32 RelidGetHash(Oid seq_relid); extern SeqTable GetGlobalSeqElm(Oid relid, GlobalSeqInfoHashBucket* bucket); extern Oid pg_get_serial_sequence_oid(text* tablename, text* columnname); +bool StrEndWith(const char *str, const char *suffix); #endif /* SEQUENCE_H */ -- Gitee From 4cb394328d0a9b0bce937f8d6be691994c754092 Mon Sep 17 00:00:00 2001 From: zwgiles Date: Mon, 28 Apr 2025 07:00:34 -0700 Subject: [PATCH 10/10] add dump test and fix dump bug --- contrib/shark/input/gs_dump_d_format.source | 3 +++ contrib/shark/output/gs_dump_d_format.source | 11 ++++++++++ .../optimizer/commands/sequence/sequence.cpp | 22 +++++++++++++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/contrib/shark/input/gs_dump_d_format.source b/contrib/shark/input/gs_dump_d_format.source index e0cfa3095d..e7a531da30 100644 --- a/contrib/shark/input/gs_dump_d_format.source +++ b/contrib/shark/input/gs_dump_d_format.source @@ -9,6 +9,8 @@ CREATE TABLE mysche.[t2](a int); CREATE TABLE [mysche].[t3](a int); INSERT INTO mysche.t1 (a) VALUES (1), (2), (3); CREATE VIEW [t4] AS SELECT * FROM mysche.t1; +CREATE TABLE table_ident(id int identity, name char(20)); +INSERT INTO table_ident values('aaa'),('bbb'),('ccc'); \! @abs_bindir@/gs_dump dump_d_database -p @portstring@ -f @abs_bindir@/dump_d.tar -F t >/dev/null 2>&1; echo $? \! @abs_bindir@/gs_restore -d restore_d_database -p @portstring@ @abs_bindir@/dump_d.tar >/dev/null 2>&1; echo $? @@ -19,6 +21,7 @@ SELECT * from mysche.t1; SELECT * from mysche.t2; SELECT * from mysche.t3; SELECT * from t4; +SELECT * from table_ident; \c contrib_regression drop database dump_d_database; diff --git a/contrib/shark/output/gs_dump_d_format.source b/contrib/shark/output/gs_dump_d_format.source index 866407378d..62d2317521 100644 --- a/contrib/shark/output/gs_dump_d_format.source +++ b/contrib/shark/output/gs_dump_d_format.source @@ -9,6 +9,9 @@ CREATE TABLE mysche.[t2](a int); CREATE TABLE [mysche].[t3](a int); INSERT INTO mysche.t1 (a) VALUES (1), (2), (3); CREATE VIEW [t4] AS SELECT * FROM mysche.t1; +CREATE TABLE table_ident(id int identity, name char(20)); +NOTICE: CREATE TABLE will create implicit sequence "table_ident_id_seq_identity" for serial column "table_ident.id" +INSERT INTO table_ident values('aaa'),('bbb'),('ccc'); \! @abs_bindir@/gs_dump dump_d_database -p @portstring@ -f @abs_bindir@/dump_d.tar -F t >/dev/null 2>&1; echo $? 0 \! @abs_bindir@/gs_restore -d restore_d_database -p @portstring@ @abs_bindir@/dump_d.tar >/dev/null 2>&1; echo $? @@ -43,6 +46,14 @@ SELECT * from t4; 3 (3 rows) +SELECT * from table_ident; + id | name +----+---------------------- + 1 | aaa + 2 | bbb + 3 | ccc +(3 rows) + \c contrib_regression drop database dump_d_database; drop database restore_d_database; diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index cc084e4547..ba473af2f6 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -2352,7 +2352,25 @@ template static void ProcessSequenceOptMaxMin(DefElem* elm, T_Form newm, bool isInit, Oid type_id, int typeMods) { if (elm != NULL && elm->arg) { - AssignInt(&(newm->max_value), defGetInt(elm)); + int maxValue = defGetInt(elm); + + if (maxValue == SEQ_MAXVALUE_8) { + AssignInt(&(newm->max_value), SEQ_MAXVALUE_8); + AssignInt(&(newm->min_value), SEQ_MINVALUE_8); + } else if (maxValue == SEQ_MAXVALUE_16) { + AssignInt(&(newm->max_value), SEQ_MAXVALUE_16); + AssignInt(&(newm->min_value), SEQ_MINVALUE_16); + } else if (maxValue == SEQ_MAXVALUE_32) { + AssignInt(&(newm->max_value), SEQ_MAXVALUE_32); + AssignInt(&(newm->min_value), SEQ_MINVALUE_32); + } else if (maxValue == SEQ_MAXVALUE) { + AssignInt(&(newm->max_value), SEQ_MAXVALUE); + AssignInt(&(newm->min_value), SEQ_MINVALUE); + } else { + int128 minValue = maxValue * (int128)-1 - (int128)1; + AssignInt(&(newm->max_value), maxValue); + AssignInt(&(newm->min_value), minValue); + } newm->log_cnt = 0; } else if (isInit || elm != NULL) { /* ascending seq */ @@ -2443,7 +2461,7 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne ProcessSequenceOptIncrementBy(elms[DEF_IDX_INCREMENT_BY], newm, isInit); ProcessSequenceOptCycle(elms[DEF_IDX_IS_CYCLED], newm, isInit); if (u_sess->attr.attr_sql.sql_compatibility == D_FORMAT && isIdentity) { - ProcessSequenceOptMaxMin(elms[DEF_IDX_MIN_VALUE], newm, isInit, type_id, typeMods); + ProcessSequenceOptMaxMin(elms[DEF_IDX_MAX_VALUE], newm, isInit, type_id, typeMods); } else { ProcessSequenceOptMax(elms[DEF_IDX_MAX_VALUE], newm, isInit); ProcessSequenceOptMin(elms[DEF_IDX_MIN_VALUE], newm, isInit); -- Gitee