diff --git a/zetasql/parser/ast_node_kind.h b/zetasql/parser/ast_node_kind.h index 063dd0e32..189816e8b 100755 --- a/zetasql/parser/ast_node_kind.h +++ b/zetasql/parser/ast_node_kind.h @@ -164,6 +164,7 @@ enum ASTNodeKind { AST_IMPORT_STATEMENT, AST_IN_EXPRESSION, AST_IN_LIST, + AST_INDEX_DEFINITION, AST_INDEX_ITEM_LIST, AST_INDEX_STORING_EXPRESSION_LIST, AST_INDEX_UNNEST_EXPRESSION_LIST, diff --git a/zetasql/parser/bison_parser.y b/zetasql/parser/bison_parser.y index 88ab0f63b..52ee36e7a 100644 --- a/zetasql/parser/bison_parser.y +++ b/zetasql/parser/bison_parser.y @@ -702,6 +702,7 @@ using zetasql::ASTDropStatement; %token KW_INTERVAL "INTERVAL" %token KW_INTO "INTO" %token KW_IS "IS" +%token KW_INDEX "INDEX" %token KW_JOIN "JOIN" %token KW_LAST "LAST" %token KW_LEFT "LEFT" @@ -834,7 +835,6 @@ using zetasql::ASTDropStatement; %token KW_IMMUTABLE "IMMUTABLE" %token KW_IMPORT "IMPORT" %token KW_INCLUDE "INCLUDE" -%token KW_INDEX "INDEX" %token KW_INOUT "INOUT" %token KW_INSERT "INSERT" %token KW_INVOKER "INVOKER" @@ -1282,6 +1282,7 @@ using zetasql::ASTDropStatement; %type table_column_definition %type table_column_schema %type table_constraint_definition +%type table_index_definition %type table_constraint_spec %type table_element %type table_element_list @@ -2624,9 +2625,18 @@ table_element_list_prefix: // table_element: table_column_definition + | table_index_definition | table_constraint_definition ; +table_index_definition: + opt_unique "INDEX" opt_identifier options_list /* HybridSE index constraint index(key=(c1),ts=c4,ttl=0m, ttl_type=absolute) */ + { + auto* node = MAKE_NODE(ASTIndexDefinition, @$, {$3, nullptr, $4}); + node->set_is_unique($1); + $$ = node; + } + ; table_column_definition: identifier table_column_schema opt_column_attributes opt_options_list { @@ -7070,6 +7080,7 @@ reserved_keyword_rule: | "INTERVAL" | "INTO" | "IS" + | "INDEX" | "JOIN" | "LAST" | "LEFT" @@ -7198,7 +7209,6 @@ keyword_as_identifier: | "IMMUTABLE" | "IMPORT" | "INCLUDE" - | "INDEX" | "INSERT" | "INOUT" | "INVOKER" diff --git a/zetasql/parser/keywords.cc b/zetasql/parser/keywords.cc index 6eb2b7834..359d56b2b 100644 --- a/zetasql/parser/keywords.cc +++ b/zetasql/parser/keywords.cc @@ -158,7 +158,7 @@ constexpr KeywordInfoPOD kAllKeywords[] = { {"in", KW_IN, KeywordInfo::kReserved}, {"include", KW_INCLUDE}, {"inout", KW_INOUT}, - {"index", KW_INDEX}, + {"index", KW_INDEX, KeywordInfo::kReserved}, {"inner", KW_INNER, KeywordInfo::kReserved}, {"insert", KW_INSERT}, {"instance_not_in_window", KW_INSTANCE_NOT_IN_WINDOW, KeywordInfo::kReserved}, diff --git a/zetasql/parser/keywords_test.cc b/zetasql/parser/keywords_test.cc index 16e9a5247..33fdd0287 100644 --- a/zetasql/parser/keywords_test.cc +++ b/zetasql/parser/keywords_test.cc @@ -237,7 +237,7 @@ TEST(ParserTest, DontAddNewReservedKeywords) { // allows new queries to work that will not work on older code. // Before changing this, co-ordinate with all engines to make sure the change // is done safely. - EXPECT_EQ(98 /* CAUTION */, num_reserved); + EXPECT_EQ(99 /* CAUTION */, num_reserved); } } // namespace diff --git a/zetasql/parser/parse_tree.cc b/zetasql/parser/parse_tree.cc index b96536fbb..4a7f23f8d 100644 --- a/zetasql/parser/parse_tree.cc +++ b/zetasql/parser/parse_tree.cc @@ -200,6 +200,7 @@ static absl::flat_hash_map CreateNodeNamesMap() { map[AST_IMPORT_STATEMENT] = "ImportStatement"; map[AST_IN_EXPRESSION] = "InExpression"; map[AST_IN_LIST] = "InList"; + map[AST_INDEX_DEFINITION] = "IndexDefinition"; map[AST_INDEX_ITEM_LIST] = "IndexItemList"; map[AST_INDEX_STORING_EXPRESSION_LIST] = "IndexStoringExpressionList"; map[AST_INDEX_UNNEST_EXPRESSION_LIST] = "IndexUnnestExpressionList"; diff --git a/zetasql/parser/parse_tree_manual.h b/zetasql/parser/parse_tree_manual.h index 95f2e4455..c3a45cd5f 100644 --- a/zetasql/parser/parse_tree_manual.h +++ b/zetasql/parser/parse_tree_manual.h @@ -5577,8 +5577,8 @@ class ASTGeneratedColumnInfo final : public ASTNode { StoredMode stored_mode_ = StoredMode::NON_STORED; }; -// Base class for CREATE TABLE elements, including column definitions and -// table constraints. +// Base class for CREATE TABLE elements, including column definitions, +// table indexs and table constraints. class ASTTableElement : public ASTNode { public: explicit ASTTableElement(ASTNodeKind kind) : ASTNode(kind) {} @@ -5703,6 +5703,34 @@ class ASTCheckConstraint final : public ASTTableConstraint { bool is_enforced_ = true; }; +class ASTIndexDefinition final : public ASTTableElement { + public: + static constexpr ASTNodeKind kConcreteNodeKind = AST_INDEX_DEFINITION; + + ASTIndexDefinition() : ASTTableElement(kConcreteNodeKind) {} + void Accept(ParseTreeVisitor* visitor, void* data) const override; + zetasql_base::StatusOr Accept( + NonRecursiveParseTreeVisitor* visitor) const override; + + const ASTIdentifier* name() const { return name_; } + const ASTColumnList* column_key_list() const { return column_key_list_; } + const ASTOptionsList* options_list() const { return options_list_; } + + bool is_unique() const { return is_unique_; } + void set_is_unique(bool is_unique) { is_unique_ = is_unique; } + private: + void InitFields() final { + FieldLoader fl(this); + fl.AddOptional(&name_, AST_IDENTIFIER); + fl.AddOptional(&column_key_list_, AST_COLUMN_LIST); + fl.AddOptional(&options_list_, AST_OPTIONS_LIST); + } + const ASTIdentifier* name_ = nullptr; + const ASTColumnList* column_key_list_ = nullptr; + const ASTOptionsList* options_list_ = nullptr; + bool is_unique_ = false; +}; + class ASTTableElementList final : public ASTNode { public: static constexpr ASTNodeKind kConcreteNodeKind = AST_TABLE_ELEMENT_LIST; diff --git a/zetasql/parser/testdata/create_external_table.test b/zetasql/parser/testdata/create_external_table.test index 3928d5dc0..59bed1662 100644 --- a/zetasql/parser/testdata/create_external_table.test +++ b/zetasql/parser/testdata/create_external_table.test @@ -662,7 +662,7 @@ create external table projectid.datasetid.tablename(x int64, y int64) create external table a.b.c.T() options () -- -ERROR: Syntax error: Unexpected ")" [at 1:31] +ERROR: Syntax error: Expected keyword INDEX but got ")" [at 1:31] create external table a.b.c.T() ^ == diff --git a/zetasql/parser/testdata/create_table.test b/zetasql/parser/testdata/create_table.test index 59ad31552..1aa0dc396 100644 --- a/zetasql/parser/testdata/create_table.test +++ b/zetasql/parser/testdata/create_table.test @@ -908,7 +908,7 @@ CREATE PRIVATE TABLE T CREATE TABLE t (); -- -ERROR: Syntax error: Unexpected ")" [at 1:17] +ERROR: Syntax error: Expected keyword INDEX but got ")" [at 1:17] CREATE TABLE t (); ^ == @@ -3065,6 +3065,361 @@ CREATE TABLE t ) == +# create table with index definition +# single key +create table t (c1 int32, c2 string, c3 int64, index(key=c2, ts=c3)); +-- +CreateTableStatement [0-68] + PathExpression [13-14] + Identifier(t) [13-14] + TableElementList [15-68] + ColumnDefinition [16-24] + Identifier(c1) [16-18] + SimpleColumnSchema [19-24] + PathExpression [19-24] + Identifier(int32) [19-24] + ColumnDefinition [26-35] + Identifier(c2) [26-28] + SimpleColumnSchema [29-35] + PathExpression [29-35] + Identifier(string) [29-35] + ColumnDefinition [37-45] + Identifier(c3) [37-39] + SimpleColumnSchema [40-45] + PathExpression [40-45] + Identifier(int64) [40-45] + IndexDefinition [46-67] + OptionsList [52-67] + OptionsEntry [53-59] + Identifier(key) [53-56] + PathExpression [57-59] + Identifier(c2) [57-59] + OptionsEntry [61-66] + Identifier(ts) [61-63] + PathExpression [64-66] + Identifier(c3) [64-66] +-- +CREATE TABLE t +( + c1 int32, + c2 string, + c3 int64, + INDEX(key = c2, ts = c3) +) +== + +# create table with index definition +# multiple keys +create table t (c1 int32, c2 string, c3 int64, index(key=(c1,c2), ts=c3)); +-- +CreateTableStatement [0-73] + PathExpression [13-14] + Identifier(t) [13-14] + TableElementList [15-73] + ColumnDefinition [16-24] + Identifier(c1) [16-18] + SimpleColumnSchema [19-24] + PathExpression [19-24] + Identifier(int32) [19-24] + ColumnDefinition [26-35] + Identifier(c2) [26-28] + SimpleColumnSchema [29-35] + PathExpression [29-35] + Identifier(string) [29-35] + ColumnDefinition [37-45] + Identifier(c3) [37-39] + SimpleColumnSchema [40-45] + PathExpression [40-45] + Identifier(int64) [40-45] + IndexDefinition [46-72] + OptionsList [52-72] + OptionsEntry [53-64] + Identifier(key) [53-56] + StructConstructorWithParens [57-64] + PathExpression [58-60] + Identifier(c1) [58-60] + PathExpression [61-63] + Identifier(c2) [61-63] + OptionsEntry [66-71] + Identifier(ts) [66-68] + PathExpression [69-71] + Identifier(c3) [69-71] +-- +CREATE TABLE t +( + c1 int32, + c2 string, + c3 int64, + INDEX(key = (c1, c2), ts = c3) +) +== + +# create table with index definition +# multiple keys, ttl_type = absolute +create table t (c1 int32, c2 string, c3 int64, index(key=(c1,c2), ts=c3, ttl_type=absolute)); +-- +CreateTableStatement [0-92] + PathExpression [13-14] + Identifier(t) [13-14] + TableElementList [15-92] + ColumnDefinition [16-24] + Identifier(c1) [16-18] + SimpleColumnSchema [19-24] + PathExpression [19-24] + Identifier(int32) [19-24] + ColumnDefinition [26-35] + Identifier(c2) [26-28] + SimpleColumnSchema [29-35] + PathExpression [29-35] + Identifier(string) [29-35] + ColumnDefinition [37-45] + Identifier(c3) [37-39] + SimpleColumnSchema [40-45] + PathExpression [40-45] + Identifier(int64) [40-45] + IndexDefinition [46-91] + OptionsList [52-91] + OptionsEntry [53-64] + Identifier(key) [53-56] + StructConstructorWithParens [57-64] + PathExpression [58-60] + Identifier(c1) [58-60] + PathExpression [61-63] + Identifier(c2) [61-63] + OptionsEntry [66-71] + Identifier(ts) [66-68] + PathExpression [69-71] + Identifier(c3) [69-71] + OptionsEntry [73-90] + Identifier(ttl_type) [73-81] + PathExpression [82-90] + Identifier(absolute) [82-90] +-- +CREATE TABLE t +( + c1 int32, + c2 string, + c3 int64, + INDEX(key = (c1, c2), ts = c3, ttl_type = absolute) +) +== + +# create table with index definition +# multiple keys, ttl_type = absolute, ttl = 365d +create table t (c1 int32, c2 string, c3 int64, index(key=(c1,c2), ts=c3, ttl_type=absolute, ttl=356d)); +-- +CreateTableStatement [0-102] + PathExpression [13-14] + Identifier(t) [13-14] + TableElementList [15-102] + ColumnDefinition [16-24] + Identifier(c1) [16-18] + SimpleColumnSchema [19-24] + PathExpression [19-24] + Identifier(int32) [19-24] + ColumnDefinition [26-35] + Identifier(c2) [26-28] + SimpleColumnSchema [29-35] + PathExpression [29-35] + Identifier(string) [29-35] + ColumnDefinition [37-45] + Identifier(c3) [37-39] + SimpleColumnSchema [40-45] + PathExpression [40-45] + Identifier(int64) [40-45] + IndexDefinition [46-101] + OptionsList [52-101] + OptionsEntry [53-64] + Identifier(key) [53-56] + StructConstructorWithParens [57-64] + PathExpression [58-60] + Identifier(c1) [58-60] + PathExpression [61-63] + Identifier(c2) [61-63] + OptionsEntry [66-71] + Identifier(ts) [66-68] + PathExpression [69-71] + Identifier(c3) [69-71] + OptionsEntry [73-90] + Identifier(ttl_type) [73-81] + PathExpression [82-90] + Identifier(absolute) [82-90] + OptionsEntry [92-100] + Identifier(ttl) [92-95] + IntervalLiteral(356d) [96-100] +-- +CREATE TABLE t +( + c1 int32, + c2 string, + c3 int64, + INDEX(key = (c1, c2), ts = c3, ttl_type = absolute, ttl = 356d) +) +== + +# create table with index definition +# multiple keys, ttl_type = latest, ttl = 0 +create table t (c1 int32, c2 string, c3 int64, index(key=(c1,c2), ts=c3, ttl_type=latest, ttl=0)); +-- +CreateTableStatement [0-97] + PathExpression [13-14] + Identifier(t) [13-14] + TableElementList [15-97] + ColumnDefinition [16-24] + Identifier(c1) [16-18] + SimpleColumnSchema [19-24] + PathExpression [19-24] + Identifier(int32) [19-24] + ColumnDefinition [26-35] + Identifier(c2) [26-28] + SimpleColumnSchema [29-35] + PathExpression [29-35] + Identifier(string) [29-35] + ColumnDefinition [37-45] + Identifier(c3) [37-39] + SimpleColumnSchema [40-45] + PathExpression [40-45] + Identifier(int64) [40-45] + IndexDefinition [46-96] + OptionsList [52-96] + OptionsEntry [53-64] + Identifier(key) [53-56] + StructConstructorWithParens [57-64] + PathExpression [58-60] + Identifier(c1) [58-60] + PathExpression [61-63] + Identifier(c2) [61-63] + OptionsEntry [66-71] + Identifier(ts) [66-68] + PathExpression [69-71] + Identifier(c3) [69-71] + OptionsEntry [73-88] + Identifier(ttl_type) [73-81] + PathExpression [82-88] + Identifier(latest) [82-88] + OptionsEntry [90-95] + Identifier(ttl) [90-93] + IntLiteral(0) [94-95] +-- +CREATE TABLE t +( + c1 int32, + c2 string, + c3 int64, + INDEX(key = (c1, c2), ts = c3, ttl_type = latest, ttl = 0) +) +== + +# create table with index definition +# multiple keys, ttl_type = absandlat, ttl = (10d,100) +create table t (c1 int32, c2 string, c3 int64, index(key=(c1,c2), ts=c3, ttl_type=absandlat, ttl=(10d, 100))); +-- +CreateTableStatement [0-109] + PathExpression [13-14] + Identifier(t) [13-14] + TableElementList [15-109] + ColumnDefinition [16-24] + Identifier(c1) [16-18] + SimpleColumnSchema [19-24] + PathExpression [19-24] + Identifier(int32) [19-24] + ColumnDefinition [26-35] + Identifier(c2) [26-28] + SimpleColumnSchema [29-35] + PathExpression [29-35] + Identifier(string) [29-35] + ColumnDefinition [37-45] + Identifier(c3) [37-39] + SimpleColumnSchema [40-45] + PathExpression [40-45] + Identifier(int64) [40-45] + IndexDefinition [46-108] + OptionsList [52-108] + OptionsEntry [53-64] + Identifier(key) [53-56] + StructConstructorWithParens [57-64] + PathExpression [58-60] + Identifier(c1) [58-60] + PathExpression [61-63] + Identifier(c2) [61-63] + OptionsEntry [66-71] + Identifier(ts) [66-68] + PathExpression [69-71] + Identifier(c3) [69-71] + OptionsEntry [73-91] + Identifier(ttl_type) [73-81] + PathExpression [82-91] + Identifier(absandlat) [82-91] + OptionsEntry [93-107] + Identifier(ttl) [93-96] + StructConstructorWithParens [97-107] + IntervalLiteral(10d) [98-101] + IntLiteral(100) [103-106] +-- +CREATE TABLE t +( + c1 int32, + c2 string, + c3 int64, + INDEX(key = (c1, c2), ts = c3, ttl_type = absandlat, ttl = (10d, 100)) +) +== + +# create table with index definition +# multiple keys, ttl_type = absorlat, ttl = (10d,100) +create table t (c1 int32, c2 string, c3 int64, index(key=(c1,c2), ts=c3, ttl_type=absorlat, ttl=(10d, 100))); +-- +CreateTableStatement [0-108] + PathExpression [13-14] + Identifier(t) [13-14] + TableElementList [15-108] + ColumnDefinition [16-24] + Identifier(c1) [16-18] + SimpleColumnSchema [19-24] + PathExpression [19-24] + Identifier(int32) [19-24] + ColumnDefinition [26-35] + Identifier(c2) [26-28] + SimpleColumnSchema [29-35] + PathExpression [29-35] + Identifier(string) [29-35] + ColumnDefinition [37-45] + Identifier(c3) [37-39] + SimpleColumnSchema [40-45] + PathExpression [40-45] + Identifier(int64) [40-45] + IndexDefinition [46-107] + OptionsList [52-107] + OptionsEntry [53-64] + Identifier(key) [53-56] + StructConstructorWithParens [57-64] + PathExpression [58-60] + Identifier(c1) [58-60] + PathExpression [61-63] + Identifier(c2) [61-63] + OptionsEntry [66-71] + Identifier(ts) [66-68] + PathExpression [69-71] + Identifier(c3) [69-71] + OptionsEntry [73-90] + Identifier(ttl_type) [73-81] + PathExpression [82-90] + Identifier(absorlat) [82-90] + OptionsEntry [92-106] + Identifier(ttl) [92-95] + StructConstructorWithParens [96-106] + IntervalLiteral(10d) [97-100] + IntLiteral(100) [102-105] +-- +CREATE TABLE t +( + c1 int32, + c2 string, + c3 int64, + INDEX(key = (c1, c2), ts = c3, ttl_type = absorlat, ttl = (10d, 100)) +) +== + # Treat FOREIGN KEY as an incomplete constraint definition rather than a valid # column definition. (See also similar test for PRIMARY KEY.) create table t (a int64, foreign key); diff --git a/zetasql/parser/testdata/describe.test b/zetasql/parser/testdata/describe.test index 249c018b4..9d9c46c85 100644 --- a/zetasql/parser/testdata/describe.test +++ b/zetasql/parser/testdata/describe.test @@ -57,37 +57,37 @@ DescribeStatement [0-18] DESCRIBE namespace.foo == -{{describe|desc}} INDEX myindex; +{{describe|desc}} `INDEX` myindex; -- ALTERNATION GROUP: describe -- -DescribeStatement [0-22] - Identifier(INDEX) [9-14] - PathExpression [15-22] - Identifier(myindex) [15-22] +DescribeStatement [0-24] + Identifier(`INDEX`) [9-16] + PathExpression [17-24] + Identifier(myindex) [17-24] -- -DESCRIBE INDEX myindex +DESCRIBE `INDEX` myindex -- ALTERNATION GROUP: desc -- -DescribeStatement [0-18] - Identifier(INDEX) [5-10] - PathExpression [11-18] - Identifier(myindex) [11-18] +DescribeStatement [0-20] + Identifier(`INDEX`) [5-12] + PathExpression [13-20] + Identifier(myindex) [13-20] -- -DESCRIBE INDEX myindex +DESCRIBE `INDEX` myindex == -describe INDEX mynamespace.myindex; +describe `INDEX` mynamespace.myindex; -- -DescribeStatement [0-34] - Identifier(INDEX) [9-14] - PathExpression [15-34] - Identifier(mynamespace) [15-26] - Identifier(myindex) [27-34] +DescribeStatement [0-36] + Identifier(`INDEX`) [9-16] + PathExpression [17-36] + Identifier(mynamespace) [17-28] + Identifier(myindex) [29-36] -- -DESCRIBE INDEX mynamespace.myindex +DESCRIBE `INDEX` mynamespace.myindex == describe FUNCTION myfunction; diff --git a/zetasql/parser/unparser.cc b/zetasql/parser/unparser.cc index 72515a928..296aae5f6 100644 --- a/zetasql/parser/unparser.cc +++ b/zetasql/parser/unparser.cc @@ -1485,7 +1485,19 @@ void Unparser::visitASTNewConstructor(const ASTNewConstructor* node, } print(")"); } - +void Unparser::visitASTIndexDefinition(const ASTIndexDefinition* node, + void* data) { + print("INDEX"); + if (node->name() != nullptr) { + node->name()->Accept(this, data); + } + if (node->column_key_list() != nullptr) { + node->column_key_list()->Accept(this, data); + } + if (node->options_list() != nullptr) { + node->options_list()->Accept(this, data); + } +} void Unparser::visitASTInferredTypeColumnSchema( const ASTInferredTypeColumnSchema* node, void* data) { UnparseColumnSchema(node, data); diff --git a/zetasql/parser/unparser.h b/zetasql/parser/unparser.h index c3c114001..d3edc1205 100644 --- a/zetasql/parser/unparser.h +++ b/zetasql/parser/unparser.h @@ -300,6 +300,8 @@ class Unparser : public ParseTreeVisitor { void* data) override; void visitASTNewConstructor(const ASTNewConstructor* node, void* data) override; + void visitASTIndexDefinition(const ASTIndexDefinition* node, + void* data) override; void visitASTInferredTypeColumnSchema(const ASTInferredTypeColumnSchema* node, void* data) override; void visitASTArrayConstructor(const ASTArrayConstructor* node,