diff --git a/README.md b/README.md index be9374ed..be9c0fb2 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ with: VERSION=1.4.2 docker run -p 9010:9010 -p 9020:9020 gcr.io/cloud-spanner-emulator/emulator:$VERSION ``` +Works on x86 and arm64 architectures. ### Via pre-built linux binaries @@ -84,6 +85,7 @@ emulator via bazel from the source root with: ```shell bazel run binaries/gateway_main ``` +Works on x86 and arm64 architectures. ### Via custom docker image @@ -101,6 +103,7 @@ docker run -p 9010:9010 -p 9020:9020 emulator The first port is the gRPC port and the second port is the REST port. +Works on x86 and arm64 architectures. ## Technical Details @@ -209,6 +212,9 @@ Notable limitations: hints. However, index names generated in the emulator cannot be used in the emulator or in production. +- The [Cloud Spanner PostgreSQL interface]( + https://cloud.google.com/spanner/docs/postgresql-interface) is not supported. + ## Frequently Asked Questions (FAQ) diff --git a/backend/schema/catalog/BUILD b/backend/schema/catalog/BUILD index 580a447d..e85204b4 100644 --- a/backend/schema/catalog/BUILD +++ b/backend/schema/catalog/BUILD @@ -48,6 +48,7 @@ cc_library( "//common:errors", "//common:limits", "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/memory", "@com_google_absl//absl/status", diff --git a/backend/schema/catalog/schema.cc b/backend/schema/catalog/schema.cc index 14085e49..a1e79171 100644 --- a/backend/schema/catalog/schema.cc +++ b/backend/schema/catalog/schema.cc @@ -25,8 +25,6 @@ #include "backend/schema/catalog/index.h" #include "backend/schema/catalog/table.h" #include "backend/schema/graph/schema_node.h" -#include "common/errors.h" -#include "absl/status/status.h" namespace google { namespace spanner { @@ -58,8 +56,10 @@ const Index* Schema::FindIndex(const std::string& index_name) const { return itr->second; } -Schema::Schema(std::unique_ptr graph) - : graph_(std::move(graph)) { +Schema::Schema(std::unique_ptr graph + ) + : graph_(std::move(graph)) +{ tables_.clear(); tables_map_.clear(); index_map_.clear(); diff --git a/backend/schema/catalog/schema.h b/backend/schema/catalog/schema.h index 614c1251..d7f4301d 100644 --- a/backend/schema/catalog/schema.h +++ b/backend/schema/catalog/schema.h @@ -18,16 +18,14 @@ #define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_SCHEMA_H_ #include +#include #include -#include "absl/container/flat_hash_map.h" -#include "absl/memory/memory.h" #include "absl/types/span.h" #include "backend/common/case.h" #include "backend/schema/catalog/index.h" #include "backend/schema/catalog/table.h" #include "backend/schema/graph/schema_graph.h" -#include "absl/status/status.h" namespace google { namespace spanner { @@ -39,9 +37,12 @@ namespace backend { // relationships. class Schema { public: - Schema() : graph_(std::make_unique()) {} + Schema() + : graph_(std::make_unique()) + {} - explicit Schema(std::unique_ptr graph); + explicit Schema(std::unique_ptr graph + ); // Returns the generation number of this schema. int64_t generation() const { return generation_; } diff --git a/backend/schema/parser/BUILD b/backend/schema/parser/BUILD index 485d8ad1..71799433 100644 --- a/backend/schema/parser/BUILD +++ b/backend/schema/parser/BUILD @@ -38,11 +38,11 @@ cc_library( "//common:errors", "//common:feature_flags", "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/memory", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - "@com_google_zetasql//zetasql/base", + "@com_google_protobuf//:protobuf_headers", ], ) @@ -55,7 +55,11 @@ cc_test( "//tests/common:proto_matchers", "//tests/common:scoped_feature_flags_setter", "@com_github_grpc_grpc//:grpc++", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", + "@com_google_protobuf//:protobuf", "@com_google_zetasql//zetasql/base/testing:status_matchers", ], ) diff --git a/backend/schema/parser/ddl_parser.cc b/backend/schema/parser/ddl_parser.cc index e4bb4199..ad0f2ec1 100644 --- a/backend/schema/parser/ddl_parser.cc +++ b/backend/schema/parser/ddl_parser.cc @@ -17,21 +17,20 @@ #include "backend/schema/parser/ddl_parser.h" -#include #include #include #include #include #include -#include "zetasql/base/logging.h" +#include "google/protobuf/descriptor.h" +#include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" -#include "absl/strings/match.h" #include "absl/strings/str_cat.h" -#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" #include "backend/schema/ddl/operations.pb.h" #include "backend/schema/parser/DDLParserTree.h" #include "backend/schema/parser/DDLParserTreeConstants.h" @@ -39,7 +38,6 @@ #include "backend/schema/parser/ddl_token_validation_utils.h" #include "common/errors.h" #include "common/feature_flags.h" -#include "absl/status/status.h" #include "zetasql/base/status_macros.h" namespace google { @@ -257,7 +255,8 @@ void SetColumnLength(const SimpleNode* length_node, ColumnDefinition* column, absl::Status VisitColumnTypeNode(const SimpleNode* column_type_node, ColumnDefinition* column_definition, ColumnType* column_type, int recursion_depth, - std::vector* errors) { + std::vector* errors +) { if (recursion_depth > 4) { return error::Internal("DDL parser exceeded max recursion stack depth"); } @@ -278,7 +277,9 @@ absl::Status VisitColumnTypeNode(const SimpleNode* column_type_node, GetChildAtIndexWithType(column_type_node, 0, JJTCOLUMN_TYPE)); ZETASQL_RETURN_IF_ERROR(VisitColumnTypeNode(column_subtype_node, column_definition, column_type->mutable_array_subtype(), - recursion_depth + 1, errors)); + recursion_depth + 1, + errors + )); } else { // Set column length constraints since this is a leaf column type node and // would contain length constraints if applicable. @@ -416,7 +417,8 @@ absl::Status VisitColumnOptionListNode(const SimpleNode* node, absl::Status VisitColumnNode(const SimpleNode* node, ColumnDefinition* column_definition, absl::string_view ddl_text, - std::vector* errors) { + std::vector* errors +) { ZETASQL_RETURN_IF_ERROR(CheckNodeType(node, JJTCOLUMN_DEF)); // Set optional column constraints and properties. @@ -430,7 +432,8 @@ absl::Status VisitColumnNode(const SimpleNode* node, ZETASQL_RETURN_IF_ERROR(VisitColumnTypeNode( child, column_definition, column_definition->mutable_properties()->mutable_column_type(), 0, - errors)); + errors + )); break; case JJTNOT_NULL: column_definition->add_constraints()->mutable_not_null()->set_nullable( @@ -678,9 +681,10 @@ absl::Status VisitRowDeletionPolicyNode(const SimpleNode* node, return VisitRowDeletionPolicyExpression(child, policy); } -absl::Status VisitCreateTableNode(const SimpleNode* node, CreateTable* table, - absl::string_view ddl_text, - std::vector* errors) { +absl::Status VisitCreateTableNode( + const SimpleNode* node, CreateTable* table, absl::string_view ddl_text, + std::vector* errors +) { ZETASQL_RETURN_IF_ERROR(CheckNodeType(node, JJTCREATE_TABLE_STATEMENT)); // Parse children nodes to set corresponding properties of table. @@ -691,8 +695,9 @@ absl::Status VisitCreateTableNode(const SimpleNode* node, CreateTable* table, table->set_table_name(child->image()); break; case JJTCOLUMN_DEF: - ZETASQL_RETURN_IF_ERROR( - VisitColumnNode(child, table->add_columns(), ddl_text, errors)); + ZETASQL_RETURN_IF_ERROR(VisitColumnNode(child, table->add_columns(), ddl_text, + errors + )); break; case JJTFOREIGN_KEY: ZETASQL_RETURN_IF_ERROR(VisitForeignKeyNode( @@ -781,16 +786,17 @@ absl::Status VisitDropStatementNode(const SimpleNode* node, return absl::OkStatus(); } -absl::Status VisitAlterTableAddColumnNode(const SimpleNode* node, - AlterTable* alter_table, - absl::string_view ddl_text, - std::vector* errors) { +absl::Status VisitAlterTableAddColumnNode( + const SimpleNode* node, AlterTable* alter_table, absl::string_view ddl_text, + std::vector* errors +) { ZETASQL_ASSIGN_OR_RETURN(const SimpleNode* column_node, GetChildAtIndexWithType(node, 2, JJTCOLUMN_DEF)); AlterColumn* alter_column = alter_table->mutable_alter_column(); alter_column->set_type(AlterColumn::ADD); return VisitColumnNode(column_node, alter_column->mutable_column(), ddl_text, - errors); + errors + ); } absl::Status VisitAlterTableDropColumnNode(const SimpleNode* node, @@ -803,10 +809,11 @@ absl::Status VisitAlterTableDropColumnNode(const SimpleNode* node, return absl::OkStatus(); } -absl::Status VisitAlterColumnAttrsNode(const SimpleNode* node, - ColumnDefinition* column_definition, - absl::string_view ddl_text, - std::vector* errors) { +absl::Status VisitAlterColumnAttrsNode( + const SimpleNode* node, ColumnDefinition* column_definition, + absl::string_view ddl_text, + std::vector* errors +) { ZETASQL_RETURN_IF_ERROR(CheckNodeType(node, JJTCOLUMN_DEF_ALTER_ATTRS)); // Set altered column attributes. @@ -817,7 +824,8 @@ absl::Status VisitAlterColumnAttrsNode(const SimpleNode* node, ZETASQL_RETURN_IF_ERROR(VisitColumnTypeNode( child, column_definition, column_definition->mutable_properties()->mutable_column_type(), 0, - errors)); + errors + )); break; case JJTNOT_NULL: column_definition->add_constraints()->mutable_not_null()->set_nullable( @@ -839,10 +847,11 @@ absl::Status VisitAlterColumnAttrsNode(const SimpleNode* node, return absl::OkStatus(); } -absl::Status VisitAlterColumnNode(const SimpleNode* node, - AlterColumn* alter_column, - absl::string_view ddl_text, - std::vector* errors) { +absl::Status VisitAlterColumnNode( + const SimpleNode* node, AlterColumn* alter_column, + absl::string_view ddl_text, + std::vector* errors +) { ZETASQL_RETURN_IF_ERROR(CheckNodeType(node, JJTCOLUMN_DEF_ALTER)); // Check the type of alter column and set corresponding properties. @@ -865,7 +874,9 @@ absl::Status VisitAlterColumnNode(const SimpleNode* node, } case JJTCOLUMN_DEF_ALTER_ATTRS: ZETASQL_RETURN_IF_ERROR(VisitAlterColumnAttrsNode( - child, alter_column->mutable_column(), ddl_text, errors)); + child, alter_column->mutable_column(), ddl_text, + errors + )); break; default: return error::Internal( @@ -874,10 +885,10 @@ absl::Status VisitAlterColumnNode(const SimpleNode* node, return absl::OkStatus(); } -absl::Status VisitAlterTableAlterColumnNode(const SimpleNode* node, - AlterTable* alter_table, - absl::string_view ddl_text, - std::vector* errors) { +absl::Status VisitAlterTableAlterColumnNode( + const SimpleNode* node, AlterTable* alter_table, absl::string_view ddl_text, + std::vector* errors +) { // Set name of the column to be altered. ZETASQL_ASSIGN_OR_RETURN(const SimpleNode* column_name_node, GetChildAtIndexWithType(node, 2, JJTNAME)); @@ -894,7 +905,8 @@ absl::Status VisitAlterTableAlterColumnNode(const SimpleNode* node, ZETASQL_ASSIGN_OR_RETURN(const SimpleNode* alter_column_node, GetChildAtIndexWithType(node, 3, JJTCOLUMN_DEF_ALTER)); return VisitAlterColumnNode(alter_column_node, alter_column, ddl_text, - errors); + errors + ); } absl::Status VisitAlterTableSetOnDelete(const SimpleNode* node, @@ -974,7 +986,8 @@ absl::Status VisitAlterRowDeletionPolicy( absl::Status VisitAlterTableNode(const SimpleNode* node, DDLStatement* statement, absl::string_view ddl_text, - std::vector* errors) { + std::vector* errors +) { ZETASQL_RETURN_IF_ERROR(CheckNodeType(node, JJTALTER_TABLE_STATEMENT)); // Name of the table to alter. @@ -987,12 +1000,15 @@ absl::Status VisitAlterTableNode(const SimpleNode* node, ZETASQL_ASSIGN_OR_RETURN(const SimpleNode* child, GetChildAtIndex(node, 1)); switch (child->getId()) { case JJTADD_COLUMN: - return VisitAlterTableAddColumnNode(node, alter_table, ddl_text, errors); + return VisitAlterTableAddColumnNode(node, alter_table, ddl_text, + errors + ); case JJTDROP_COLUMN: return VisitAlterTableDropColumnNode(node, alter_table); case JJTALTER_COLUMN: return VisitAlterTableAlterColumnNode(node, alter_table, ddl_text, - errors); + errors + ); case JJTSET_ON_DELETE: return VisitAlterTableSetOnDelete(node, alter_table); case JJTFOREIGN_KEY: @@ -1021,7 +1037,8 @@ absl::Status VisitAlterTableNode(const SimpleNode* node, absl::StatusOr BuildDDLStatement( const SimpleNode* root, absl::string_view ddl_text, - std::vector* errors) { + std::vector* errors +) { ZETASQL_RETURN_IF_ERROR(CheckNodeType(root, JJTDDL_STATEMENT)); if (root->jjtGetNumChildren() != 1) { return error::Internal( @@ -1034,7 +1051,9 @@ absl::StatusOr BuildDDLStatement( switch (child->getId()) { case JJTCREATE_TABLE_STATEMENT: ZETASQL_RETURN_IF_ERROR(VisitCreateTableNode( - child, statement.mutable_create_table(), ddl_text, errors)); + child, statement.mutable_create_table(), ddl_text, + errors + )); break; case JJTCREATE_INDEX_STATEMENT: ZETASQL_RETURN_IF_ERROR( @@ -1045,7 +1064,9 @@ absl::StatusOr BuildDDLStatement( break; } case JJTALTER_TABLE_STATEMENT: - ZETASQL_RETURN_IF_ERROR(VisitAlterTableNode(child, &statement, ddl_text, errors)); + ZETASQL_RETURN_IF_ERROR(VisitAlterTableNode(child, &statement, ddl_text, + errors + )); break; case JJTANALYZE_STATEMENT: // Intentionally no-op @@ -1103,7 +1124,9 @@ absl::StatusOr ParseCreateDatabase( return BuildCreateDatabaseStatement(node.get()); } -absl::StatusOr ParseDDLStatement(absl::string_view input) { +absl::StatusOr ParseDDLStatement( + absl::string_view input +) { // Parse input statement into the root node. ZETASQL_ASSIGN_OR_RETURN(std::unique_ptr node, ParseDDLStatementToNode(input)); @@ -1111,23 +1134,15 @@ absl::StatusOr ParseDDLStatement(absl::string_view input) { // Try to read root node as a valid DDLStatement. std::vector errors; DDLStatement statement; - ZETASQL_ASSIGN_OR_RETURN(statement, BuildDDLStatement(node.get(), input, &errors)); + ZETASQL_ASSIGN_OR_RETURN(statement, BuildDDLStatement(node.get(), input, + &errors + )); if (!errors.empty()) { return error::DDLStatementWithErrors(input, errors); } return statement; } -absl::StatusOr ParseDDLStatements( - absl::Span statements) { - Schema schema; - for (absl::string_view statement : statements) { - ZETASQL_ASSIGN_OR_RETURN(*schema.add_ddl_statements(), - ParseDDLStatement(statement)); - } - return schema; -} - } // namespace ddl } // namespace backend } // namespace emulator diff --git a/backend/schema/parser/ddl_parser.h b/backend/schema/parser/ddl_parser.h index 3b64dedf..b4ad9ab1 100644 --- a/backend/schema/parser/ddl_parser.h +++ b/backend/schema/parser/ddl_parser.h @@ -17,16 +17,17 @@ #ifndef THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_PARSER_DDL_PARSER_H_ #define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_PARSER_DDL_PARSER_H_ +#include + #include "absl/status/statusor.h" #include "absl/strings/string_view.h" -#include "absl/types/span.h" #include "backend/schema/ddl/operations.pb.h" -#include "absl/status/status.h" namespace google { namespace spanner { namespace emulator { namespace backend { + namespace ddl { // The option to enable the use of cloud spanner commit timestamps for a column. @@ -37,11 +38,9 @@ absl::StatusOr ParseCreateDatabase( absl::string_view create_statement); // Parses a single DDL statement. -absl::StatusOr ParseDDLStatement(absl::string_view input); - -// Parses a list of DDL statements. -absl::StatusOr ParseDDLStatements( - absl::Span statements); +absl::StatusOr ParseDDLStatement( + absl::string_view input +); } // namespace ddl } // namespace backend diff --git a/backend/schema/parser/ddl_parser_test.cc b/backend/schema/parser/ddl_parser_test.cc index 4b8db94d..50ccc7e9 100644 --- a/backend/schema/parser/ddl_parser_test.cc +++ b/backend/schema/parser/ddl_parser_test.cc @@ -16,12 +16,21 @@ #include "backend/schema/parser/ddl_parser.h" +#include +#include +#include +#include + #include "gmock/gmock.h" #include "gtest/gtest.h" #include "zetasql/base/testing/status_matchers.h" #include "tests/common/proto_matchers.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/substitute.h" #include "common/feature_flags.h" #include "tests/common/scoped_feature_flags_setter.h" +#include "zetasql/base/status_macros.h" namespace google { namespace spanner { @@ -1895,14 +1904,14 @@ TEST(AllowCommitTimestamp, CannotParseInvalidOptionValue) { } TEST(ParseToken, CannotParseUnterminatedTripleQuote) { - static const char* const statements[] = { + static const char *const statements[] = { "'''", "''''", "'''''", "'''abc", "'''abc''", "'''abc'", "r'''abc", "b'''abc", "\"\"\"", "\"\"\"\"", "\"\"\"\"\"", "rb\"\"\"abc", "\"\"\"abc", "\"\"\"abc\"\"", "\"\"\"abc\"", "r\"\"\"abc", "b\"\"\"abc", "rb\"\"\"abc", }; - for (const char* statement : statements) { + for (const char *statement : statements) { EXPECT_THAT( ParseDDLStatement(statement), StatusIs(absl::StatusCode::kInvalidArgument, diff --git a/backend/schema/updater/BUILD b/backend/schema/updater/BUILD index c73b36b0..7f944b18 100644 --- a/backend/schema/updater/BUILD +++ b/backend/schema/updater/BUILD @@ -43,7 +43,10 @@ cc_test( "//backend/schema/ddl:operations_cc_proto", "//tests/common:proto_matchers", "@com_github_grpc_grpc//:grpc++", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_googletest//:gtest_main", + "@com_google_protobuf//:protobuf", "@com_google_zetasql//zetasql/base/testing:status_matchers", "@com_google_zetasql//zetasql/public:type", ], @@ -116,14 +119,23 @@ cc_library( "//common:errors", "//common:limits", "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/meta:type_traits", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/time", "@com_google_absl//absl/types:span", "@com_google_protobuf//:protobuf_headers", + "@com_google_zetasql//zetasql/base:logging", + "@com_google_zetasql//zetasql/base:ret_check", "@com_google_zetasql//zetasql/public:analyzer", + "@com_google_zetasql//zetasql/public:analyzer_options", + "@com_google_zetasql//zetasql/public:analyzer_output", + "@com_google_zetasql//zetasql/public:catalog", + "@com_google_zetasql//zetasql/public:function", + "@com_google_zetasql//zetasql/public:function_cc_proto", "@com_google_zetasql//zetasql/public:simple_catalog", "@com_google_zetasql//zetasql/public:type", "@com_google_zetasql//zetasql/resolved_ast", diff --git a/backend/schema/updater/ddl_type_conversion.cc b/backend/schema/updater/ddl_type_conversion.cc index de5f33bb..6a1e92ef 100644 --- a/backend/schema/updater/ddl_type_conversion.cc +++ b/backend/schema/updater/ddl_type_conversion.cc @@ -16,6 +16,8 @@ #include "backend/schema/updater/ddl_type_conversion.h" +#include + #include "absl/status/statusor.h" #include "backend/schema/ddl/operations.pb.h" #include "zetasql/base/ret_check.h" @@ -27,7 +29,9 @@ namespace emulator { namespace backend { absl::StatusOr DDLColumnTypeToGoogleSqlType( - const ddl::ColumnType& ddl_type, zetasql::TypeFactory* type_factory) { + const ddl::ColumnType& ddl_type, + zetasql::TypeFactory* type_factory +) { ZETASQL_RET_CHECK(ddl_type.has_type()) << "No type field specification in " << "ddl::ColumnType input: " << ddl_type.ShortDebugString(); @@ -63,7 +67,9 @@ absl::StatusOr DDLColumnTypeToGoogleSqlType( } ZETASQL_ASSIGN_OR_RETURN( auto array_element_type, - DDLColumnTypeToGoogleSqlType(ddl_type.array_subtype(), type_factory)); + DDLColumnTypeToGoogleSqlType(ddl_type.array_subtype(), + type_factory + )); ZETASQL_RET_CHECK_NE(array_element_type, nullptr); const zetasql::Type* array_type; ZETASQL_RETURN_IF_ERROR( diff --git a/backend/schema/updater/ddl_type_conversion.h b/backend/schema/updater/ddl_type_conversion.h index f0aa9974..eb221316 100644 --- a/backend/schema/updater/ddl_type_conversion.h +++ b/backend/schema/updater/ddl_type_conversion.h @@ -17,10 +17,11 @@ #ifndef THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_UPDATER_DDL_TYPE_CONVERSION_H_ #define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_UPDATER_DDL_TYPE_CONVERSION_H_ +#include + #include "zetasql/public/type.h" #include "absl/status/statusor.h" #include "backend/schema/ddl/operations.pb.h" -#include "absl/status/status.h" namespace google { namespace spanner { @@ -29,7 +30,9 @@ namespace backend { // Converts the ColumnType in DDL statements to zetasql::Type. absl::StatusOr DDLColumnTypeToGoogleSqlType( - const ddl::ColumnType& ddl_type, zetasql::TypeFactory* type_factory); + const ddl::ColumnType& ddl_type, + zetasql::TypeFactory* type_factory +); // Converts zetasql::Type to its equivalent DDL ColumnType. Returns a // ddl::ColumnType::UNKNOWN_TYPE type if the passed in googlesql type is not a diff --git a/backend/schema/updater/ddl_type_conversion_test.cc b/backend/schema/updater/ddl_type_conversion_test.cc index 5b8e9520..35373482 100644 --- a/backend/schema/updater/ddl_type_conversion_test.cc +++ b/backend/schema/updater/ddl_type_conversion_test.cc @@ -16,12 +16,20 @@ #include "backend/schema/updater/ddl_type_conversion.h" +#include +#include +#include + +#include "google/protobuf/descriptor.pb.h" #include "zetasql/public/type.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "zetasql/base/testing/status_matchers.h" #include "tests/common/proto_matchers.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "backend/schema/ddl/operations.pb.h" +#include "zetasql/base/status_macros.h" namespace google { namespace spanner { @@ -34,9 +42,9 @@ class DDLColumnTypeToGoogleSqlTypeTest : public ::testing::Test { public: DDLColumnTypeToGoogleSqlTypeTest() {} - ddl::ColumnType MakeDDLType(ddl::ColumnType::Type type_enum) { + ddl::ColumnType MakeColumnType(ddl::ColumnType::Type column_type) { ddl::ColumnType ddl_type; - ddl_type.set_type(type_enum); + ddl_type.set_type(column_type); return ddl_type; } @@ -45,7 +53,7 @@ class DDLColumnTypeToGoogleSqlTypeTest : public ::testing::Test { }; TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Float64) { - auto ddl_type = MakeDDLType(ddl::ColumnType::FLOAT64); + auto ddl_type = MakeColumnType(ddl::ColumnType::FLOAT64); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_double())); @@ -54,7 +62,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Float64) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Int64) { - auto ddl_type = MakeDDLType(ddl::ColumnType::INT64); + auto ddl_type = MakeColumnType(ddl::ColumnType::INT64); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_int64())); @@ -63,7 +71,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Int64) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Bool) { - auto ddl_type = MakeDDLType(ddl::ColumnType::BOOL); + auto ddl_type = MakeColumnType(ddl::ColumnType::BOOL); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_bool())); @@ -72,7 +80,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Bool) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, String) { - auto ddl_type = MakeDDLType(ddl::ColumnType::STRING); + auto ddl_type = MakeColumnType(ddl::ColumnType::STRING); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_string())); @@ -81,7 +89,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, String) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Bytes) { - auto ddl_type = MakeDDLType(ddl::ColumnType::BYTES); + auto ddl_type = MakeColumnType(ddl::ColumnType::BYTES); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_bytes())); @@ -90,7 +98,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Bytes) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Timestamp) { - auto ddl_type = MakeDDLType(ddl::ColumnType::TIMESTAMP); + auto ddl_type = MakeColumnType(ddl::ColumnType::TIMESTAMP); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_timestamp())); @@ -99,7 +107,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Timestamp) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Date) { - auto ddl_type = MakeDDLType(ddl::ColumnType::DATE); + auto ddl_type = MakeColumnType(ddl::ColumnType::DATE); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_date())); @@ -108,7 +116,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Date) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Numeric) { - auto ddl_type = MakeDDLType(ddl::ColumnType::NUMERIC); + auto ddl_type = MakeColumnType(ddl::ColumnType::NUMERIC); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_numeric())); @@ -117,7 +125,7 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Numeric) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Json) { - auto ddl_type = MakeDDLType(ddl::ColumnType::JSON); + auto ddl_type = MakeColumnType(ddl::ColumnType::JSON); ZETASQL_ASSERT_OK_AND_ASSIGN(const zetasql::Type* converted_type, DDLColumnTypeToGoogleSqlType(ddl_type, &type_factory_)); EXPECT_TRUE(converted_type->Equals(type_factory_.get_json())); @@ -126,8 +134,8 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Json) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Array) { - auto array_element_type = MakeDDLType(ddl::ColumnType::STRING); - auto array_type = MakeDDLType(ddl::ColumnType::ARRAY); + auto array_element_type = MakeColumnType(ddl::ColumnType::STRING); + auto array_type = MakeColumnType(ddl::ColumnType::ARRAY); *(array_type.mutable_array_subtype()) = array_element_type; ZETASQL_ASSERT_OK_AND_ASSIGN( const zetasql::Type* converted_type, @@ -143,11 +151,11 @@ TEST_F(DDLColumnTypeToGoogleSqlTypeTest, Array) { } TEST_F(DDLColumnTypeToGoogleSqlTypeTest, ArrayOfArray) { - auto array_element_type = MakeDDLType(ddl::ColumnType::STRING); - auto array_type1 = MakeDDLType(ddl::ColumnType::ARRAY); + auto array_element_type = MakeColumnType(ddl::ColumnType::STRING); + auto array_type1 = MakeColumnType(ddl::ColumnType::ARRAY); *(array_type1.mutable_array_subtype()) = array_element_type; - auto array_type2 = MakeDDLType(ddl::ColumnType::ARRAY); + auto array_type2 = MakeColumnType(ddl::ColumnType::ARRAY); *(array_type2.mutable_array_subtype()) = array_type1; EXPECT_THAT(DDLColumnTypeToGoogleSqlType(array_type2, &type_factory_), diff --git a/backend/schema/updater/schema_updater.cc b/backend/schema/updater/schema_updater.cc index f4fdee8c..886474b8 100644 --- a/backend/schema/updater/schema_updater.cc +++ b/backend/schema/updater/schema_updater.cc @@ -16,26 +16,38 @@ #include "backend/schema/updater/schema_updater.h" -#include #include +#include #include #include #include #include #include +#include "zetasql/base/logging.h" #include "google/protobuf/repeated_field.h" #include "zetasql/public/analyzer.h" +#include "zetasql/public/analyzer_options.h" +#include "zetasql/public/analyzer_output.h" +#include "zetasql/public/catalog.h" +#include "zetasql/public/function.h" +#include "zetasql/public/function.pb.h" #include "zetasql/public/simple_catalog.h" #include "zetasql/public/type.h" #include "zetasql/resolved_ast/resolved_ast.h" +#include "zetasql/resolved_ast/resolved_node.h" #include "zetasql/resolved_ast/resolved_node_kind.pb.h" #include "absl/algorithm/container.h" +#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" +#include "absl/meta/type_traits.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/match.h" -#include "absl/types/optional.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "absl/types/span.h" #include "backend/query/analyzer_options.h" #include "backend/query/catalog.h" #include "backend/query/query_engine_options.h" @@ -62,6 +74,7 @@ #include "backend/schema/verifiers/foreign_key_verifiers.h" #include "common/errors.h" #include "common/limits.h" +#include "zetasql/base/ret_check.h" #include "zetasql/base/status_macros.h" namespace google { @@ -133,7 +146,8 @@ class SchemaUpdaterImpl { // Applies the given `statement` on to `latest_schema_`. absl::StatusOr> ApplyDDLStatement( - absl::string_view statement); + absl::string_view statement + ); // Run any pending schema actions resulting from the schema change statements. absl::Status RunPendingActions( @@ -348,7 +362,8 @@ absl::Status SchemaUpdaterImpl::DropNode(const SchemaNode* node) { } absl::StatusOr> -SchemaUpdaterImpl::ApplyDDLStatement(absl::string_view statement) { +SchemaUpdaterImpl::ApplyDDLStatement(absl::string_view statement +) { if (statement.empty()) { return error::EmptyDDLStatement(); } @@ -356,7 +371,8 @@ SchemaUpdaterImpl::ApplyDDLStatement(absl::string_view statement) { // Apply the statement to the schema graph. ZETASQL_RET_CHECK(!editor_->HasModifications()); ZETASQL_ASSIGN_OR_RETURN(const auto& ddl_statement, - ddl::ParseDDLStatement(statement)); + ddl::ParseDDLStatement(statement + )); switch (ddl_statement.kind_case()) { case ddl::DDLStatement::kCreateTable: { @@ -387,7 +403,8 @@ SchemaUpdaterImpl::ApplyDDLStatement(absl::string_view statement) { << ddl_statement.kind_case(); } ZETASQL_ASSIGN_OR_RETURN(auto new_schema_graph, editor_->CanonicalizeGraph()); - return std::make_unique(std::move(new_schema_graph)); + return std::make_unique(std::move(new_schema_graph) + ); } absl::StatusOr> @@ -404,7 +421,10 @@ SchemaUpdaterImpl::ApplyDDLStatements( latest_schema_->GetSchemaGraph(), statement_context_); // If there is a semantic validation error, then we return right away. - ZETASQL_ASSIGN_OR_RETURN(auto new_schema, ApplyDDLStatement(statement)); + ZETASQL_ASSIGN_OR_RETURN( + auto new_schema, + ApplyDDLStatement(statement + )); // We save every schema snapshot as verifiers/backfillers from the // current/next statement may need to refer to the previous/current @@ -559,7 +579,8 @@ absl::Status SchemaUpdaterImpl::InitColumnNameAndTypesFromTable( ZETASQL_ASSIGN_OR_RETURN( const zetasql::Type* type, DDLColumnTypeToGoogleSqlType(ddl_column.properties().column_type(), - type_factory_)); + type_factory_ + )); name_and_types->emplace_back(ddl_column.column_name(), type); } } else { @@ -678,9 +699,11 @@ absl::Status SchemaUpdaterImpl::SetColumnDefinition( // Process any changes in column definition. if (ddl_column.has_properties() && ddl_column.properties().has_column_type()) { - ZETASQL_ASSIGN_OR_RETURN(const zetasql::Type* column_type, - DDLColumnTypeToGoogleSqlType( - ddl_column.properties().column_type(), type_factory_)); + ZETASQL_ASSIGN_OR_RETURN( + const zetasql::Type* column_type, + DDLColumnTypeToGoogleSqlType(ddl_column.properties().column_type(), + type_factory_ + )); modifier->set_type(column_type); ddl::ColumnProperties properties = ddl_column.properties(); diff --git a/backend/schema/updater/schema_updater.h b/backend/schema/updater/schema_updater.h index 1ab2c028..bb46e8b5 100644 --- a/backend/schema/updater/schema_updater.h +++ b/backend/schema/updater/schema_updater.h @@ -25,11 +25,10 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "absl/types/span.h" #include "backend/common/ids.h" #include "backend/schema/catalog/schema.h" -#include "absl/status/status.h" -#include "zetasql/base/status_macros.h" namespace google { namespace spanner { diff --git a/backend/schema/updater/schema_updater_tests/BUILD b/backend/schema/updater/schema_updater_tests/BUILD index e7c26e3e..15070559 100644 --- a/backend/schema/updater/schema_updater_tests/BUILD +++ b/backend/schema/updater/schema_updater_tests/BUILD @@ -39,11 +39,9 @@ cc_library( "//common:limits", "//tests/common:proto_matchers", "@com_github_grpc_grpc//:grpc++", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", - "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", "@com_google_googletest//:gtest", "@com_google_zetasql//zetasql/base/testing:status_matchers", "@com_google_zetasql//zetasql/public:type", diff --git a/backend/schema/updater/schema_updater_tests/base.cc b/backend/schema/updater/schema_updater_tests/base.cc index 9de4df01..5d8a85d8 100644 --- a/backend/schema/updater/schema_updater_tests/base.cc +++ b/backend/schema/updater/schema_updater_tests/base.cc @@ -20,6 +20,8 @@ #include #include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" #include "backend/schema/updater/schema_updater.h" namespace google { @@ -29,18 +31,26 @@ namespace backend { namespace test { absl::StatusOr> SchemaUpdaterTest::CreateSchema( - absl::Span statements) { - return UpdateSchema(/*base_schema=*/nullptr, statements); + absl::Span statements +) { + return UpdateSchema(/*base_schema=*/nullptr, + statements + ); } absl::StatusOr> SchemaUpdaterTest::UpdateSchema( - const Schema* base_schema, absl::Span statements) { + const Schema* base_schema, + absl::Span statements +) { SchemaUpdater updater; SchemaChangeContext context{.type_factory = &type_factory_, .table_id_generator = &table_id_generator_, .column_id_generator = &column_id_generator_}; return updater.ValidateSchemaFromDDL( - SchemaChangeOperation{.statements = statements}, context, base_schema); + SchemaChangeOperation{ + .statements = statements, + }, + context, base_schema); } } // namespace test diff --git a/backend/schema/updater/schema_updater_tests/base.h b/backend/schema/updater/schema_updater_tests/base.h index 6029c502..35462249 100644 --- a/backend/schema/updater/schema_updater_tests/base.h +++ b/backend/schema/updater/schema_updater_tests/base.h @@ -17,22 +17,23 @@ #ifndef THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_UPDATER_SCHEMA_UPDATER_TESTS_BASE_H_ #define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_UPDATER_SCHEMA_UPDATER_TESTS_BASE_H_ -#include #include +#include +#include #include "zetasql/public/type.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "zetasql/base/testing/status_matchers.h" #include "tests/common/proto_matchers.h" -#include "absl/memory/memory.h" -#include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/strings/substitute.h" -#include "absl/time/time.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" #include "backend/common/ids.h" -#include "backend/schema/catalog/column.h" #include "backend/schema/catalog/foreign_key.h" +#include "backend/schema/catalog/schema.h" #include "backend/schema/catalog/table.h" #include "backend/schema/graph/schema_graph.h" #include "backend/schema/graph/schema_graph_editor.h" @@ -148,10 +149,13 @@ const T* AssertNotNull(const T* value, const char* file, int line) { class SchemaUpdaterTest : public testing::Test { public: absl::StatusOr> CreateSchema( - absl::Span statements); + absl::Span statements + ); absl::StatusOr> UpdateSchema( - const Schema* base_schema, absl::Span statements); + const Schema* base_schema, + absl::Span statements + ); protected: zetasql::TypeFactory type_factory_; diff --git a/build/bazel/grpc_gateway.bzl b/build/bazel/grpc_gateway.bzl index c184c614..4103f19a 100644 --- a/build/bazel/grpc_gateway.bzl +++ b/build/bazel/grpc_gateway.bzl @@ -118,17 +118,17 @@ generate_grpc_gateway_file = rule( "yaml_config": attr.label(allow_files = True), "protoc": attr.label( executable = True, - cfg = "host", + cfg = "exec", default = "@com_google_protobuf//:protoc", ), "protoc_gen_grpc_gateway": attr.label( executable = True, - cfg = "host", + cfg = "exec", default = GRPC_GATEWAY_PKG + ":" + GRPC_GATEWAY_BIN, ), "fix_grpc_gateway": attr.label( executable = True, - cfg = "host", + cfg = "exec", default = ":fix_grpc_gateway", ), }, diff --git a/common/feature_flags.h b/common/feature_flags.h index 1b100613..92ee0397 100644 --- a/common/feature_flags.h +++ b/common/feature_flags.h @@ -32,7 +32,7 @@ class EmulatorFeatureFlags { struct Flags { bool enable_stored_generated_columns = true; bool enable_check_constraint = true; - bool enable_column_default_values = false; + bool enable_column_default_values = true; }; static const EmulatorFeatureFlags& instance() { diff --git a/common/feature_flags_test.cc b/common/feature_flags_test.cc index eadcc6a9..75515e39 100644 --- a/common/feature_flags_test.cc +++ b/common/feature_flags_test.cc @@ -33,32 +33,21 @@ TEST(EmulatorFeatureFlags, Basic) { EXPECT_TRUE(features.flags().enable_stored_generated_columns); EXPECT_TRUE(features.flags().enable_check_constraint); + EXPECT_TRUE(features.flags().enable_column_default_values); { EmulatorFeatureFlags::Flags flags; flags.enable_stored_generated_columns = false; flags.enable_check_constraint = false; + flags.enable_column_default_values = false; test::ScopedEmulatorFeatureFlagsSetter setter(flags); EXPECT_FALSE(features.flags().enable_stored_generated_columns); EXPECT_FALSE(features.flags().enable_check_constraint); + EXPECT_FALSE(features.flags().enable_column_default_values); } EXPECT_TRUE(features.flags().enable_stored_generated_columns); EXPECT_TRUE(features.flags().enable_check_constraint); -} - -TEST(EmulatorFeatureFlags, DefaultValuesFlag) { - const EmulatorFeatureFlags& features = EmulatorFeatureFlags::instance(); - - EXPECT_FALSE(features.flags().enable_column_default_values); - - { - EmulatorFeatureFlags::Flags flags; - flags.enable_column_default_values = true; - test::ScopedEmulatorFeatureFlagsSetter setter(flags); - EXPECT_TRUE(features.flags().enable_column_default_values); - } - - EXPECT_FALSE(features.flags().enable_column_default_values); + EXPECT_TRUE(features.flags().enable_column_default_values); } } // namespace diff --git a/frontend/converters/BUILD b/frontend/converters/BUILD index e198a637..b7e7e9cf 100644 --- a/frontend/converters/BUILD +++ b/frontend/converters/BUILD @@ -231,9 +231,13 @@ cc_library( deps = [ "//common:errors", "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_googleapis//google/spanner/v1:spanner_cc_grpc", + "@com_google_protobuf//:protobuf_headers", + "@com_google_zetasql//zetasql/base:ret_check", "@com_google_zetasql//zetasql/public:type", + "@com_google_zetasql//zetasql/public:type_cc_proto", ], ) @@ -244,7 +248,12 @@ cc_test( ":types", "//tests/common:proto_matchers", "@com_github_grpc_grpc//:grpc++", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/types:span", + "@com_google_googleapis//google/spanner/v1:spanner_cc_grpc", "@com_google_googletest//:gtest_main", + "@com_google_protobuf//:protobuf", "@com_google_zetasql//zetasql/base/testing:status_matchers", "@com_google_zetasql//zetasql/public:type", ], @@ -292,10 +301,12 @@ cc_library( ":values", "//backend/query:query_engine", "//common:errors", + "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_googleapis//google/spanner/v1:spanner_cc_grpc", "@com_google_protobuf//:cc_wkt_protos", "@com_google_zetasql//zetasql/public:type", + "@com_google_zetasql//zetasql/public:value", ], ) diff --git a/frontend/converters/query.cc b/frontend/converters/query.cc index c7b3ec14..7da63302 100644 --- a/frontend/converters/query.cc +++ b/frontend/converters/query.cc @@ -17,13 +17,18 @@ #include "frontend/converters/query.h" #include +#include #include #include +#include "google/protobuf/struct.pb.h" +#include "google/spanner/v1/type.pb.h" #include "zetasql/public/type.h" +#include "zetasql/public/value.h" #include "absl/status/statusor.h" #include "frontend/converters/types.h" #include "frontend/converters/values.h" +#include "zetasql/base/status_macros.h" namespace google { namespace spanner { @@ -33,7 +38,8 @@ namespace frontend { absl::StatusOr QueryFromProto( std::string sql, const google::protobuf::Struct& params, google::protobuf::Map param_types, - zetasql::TypeFactory* type_factory) { + zetasql::TypeFactory* type_factory +) { std::map declared; std::map undeclared; for (const auto& [name, proto_value] : params.fields()) { @@ -44,7 +50,9 @@ absl::StatusOr QueryFromProto( } else { const spanner::v1::Type& proto_type = param_type_iter->second; const zetasql::Type* type; - ZETASQL_RETURN_IF_ERROR(TypeFromProto(proto_type, type_factory, &type)); + ZETASQL_RETURN_IF_ERROR(TypeFromProto(proto_type, type_factory, + &type + )); ZETASQL_ASSIGN_OR_RETURN(declared[name], ValueFromProto(proto_value, type)); } } diff --git a/frontend/converters/query.h b/frontend/converters/query.h index 2c05e9c6..f4307ceb 100644 --- a/frontend/converters/query.h +++ b/frontend/converters/query.h @@ -34,7 +34,8 @@ namespace frontend { absl::StatusOr QueryFromProto( std::string sql, const google::protobuf::Struct& params, google::protobuf::Map param_types, - zetasql::TypeFactory* type_factory); + zetasql::TypeFactory* type_factory +); } // namespace frontend } // namespace emulator diff --git a/frontend/converters/types.cc b/frontend/converters/types.cc index 30e4f807..75d8b579 100644 --- a/frontend/converters/types.cc +++ b/frontend/converters/types.cc @@ -16,10 +16,23 @@ #include "frontend/converters/types.h" +#include +#include #include +#include "google/spanner/v1/type.pb.h" +#include "google/protobuf/descriptor.h" +#include "zetasql/public/type.h" +#include "zetasql/public/type.pb.h" +#include "zetasql/public/types/array_type.h" +#include "zetasql/public/types/enum_type.h" +#include "zetasql/public/types/proto_type.h" +#include "zetasql/public/types/struct_type.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "common/errors.h" +#include "zetasql/base/ret_check.h" #include "zetasql/base/status_macros.h" namespace google { @@ -27,9 +40,10 @@ namespace spanner { namespace emulator { namespace frontend { -absl::Status TypeFromProto(const google::spanner::v1::Type& type_pb, - zetasql::TypeFactory* factory, - const zetasql::Type** type) { +absl::Status TypeFromProto( + const google::spanner::v1::Type& type_pb, zetasql::TypeFactory* factory, + const zetasql::Type** type +) { switch (type_pb.code()) { case google::spanner::v1::TypeCode::BOOL: { *type = factory->get_bool(); @@ -81,8 +95,9 @@ absl::Status TypeFromProto(const google::spanner::v1::Type& type_pb, if (!type_pb.has_array_element_type()) { return error::ArrayTypeMustSpecifyElementType(type_pb.DebugString()); } - ZETASQL_RETURN_IF_ERROR( - TypeFromProto(type_pb.array_element_type(), factory, &element_type)) + ZETASQL_RETURN_IF_ERROR(TypeFromProto(type_pb.array_element_type(), factory, + &element_type + )) << "\nWhen parsing array element type of " << type_pb.DebugString(); ZETASQL_RETURN_IF_ERROR(factory->MakeArrayType(element_type, type)) << "\nWhen parsing " << type_pb.DebugString(); @@ -94,7 +109,9 @@ absl::Status TypeFromProto(const google::spanner::v1::Type& type_pb, for (int i = 0; i < type_pb.struct_type().fields_size(); ++i) { const zetasql::Type* type; ZETASQL_RETURN_IF_ERROR(TypeFromProto(type_pb.struct_type().fields(i).type(), - factory, &type)) + factory, + &type + )) << "\nWhen parsing field #" << i << " of " << type_pb.DebugString(); zetasql::StructField field(type_pb.struct_type().fields(i).name(), type); diff --git a/frontend/converters/types.h b/frontend/converters/types.h index f9544a57..96adde1c 100644 --- a/frontend/converters/types.h +++ b/frontend/converters/types.h @@ -20,7 +20,6 @@ #include "google/spanner/v1/type.pb.h" #include "zetasql/public/type.h" #include "absl/status/status.h" -#include "absl/status/status.h" namespace google { namespace spanner { @@ -33,9 +32,10 @@ namespace frontend { // function will be owned by the supplied type factory. An unspecified type // or incorrect type specification will return an appropriate error and leave // type unchanged. -absl::Status TypeFromProto(const google::spanner::v1::Type& type_pb, - zetasql::TypeFactory* factory, - const zetasql::Type** type); +absl::Status TypeFromProto( + const google::spanner::v1::Type& type_pb, zetasql::TypeFactory* factory, + const zetasql::Type** type +); // Converts a ZetaSQL type to a Cloud Spanner type proto. // diff --git a/frontend/converters/types_test.cc b/frontend/converters/types_test.cc index 5d7c9746..2e45e8f2 100644 --- a/frontend/converters/types_test.cc +++ b/frontend/converters/types_test.cc @@ -16,15 +16,24 @@ #include "frontend/converters/types.h" +#include #include #include #include +#include "google/spanner/v1/type.pb.h" +#include "google/protobuf/descriptor.pb.h" #include "zetasql/public/type.h" +#include "zetasql/public/types/array_type.h" +#include "zetasql/public/types/struct_type.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "zetasql/base/testing/status_matchers.h" #include "tests/common/proto_matchers.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/types/span.h" +#include "zetasql/base/status_macros.h" namespace google { namespace spanner { @@ -48,7 +57,12 @@ using zetasql::types::NumericType; using zetasql::types::StringType; using zetasql::types::TimestampType; -TEST(TypeProtos, ConvertsBasicTypesBetweenTypesAndProtos) { +class TypeProtos : public ::testing::Test { + public: + TypeProtos() = default; +}; + +TEST_F(TypeProtos, ConvertsBasicTypesBetweenTypesAndProtos) { zetasql::TypeFactory factory; const zetasql::Type* str_int_pair_type; ZETASQL_ASSERT_OK(factory.MakeStructType( @@ -121,7 +135,8 @@ TEST(TypeProtos, ConvertsBasicTypesBetweenTypesAndProtos) { // Check proto -> type conversion. const zetasql::Type* actual_type; ZETASQL_EXPECT_OK(TypeFromProto(PARSE_TEXT_PROTO(expected_type_pb_txt), &factory, - &actual_type)); + &actual_type + )); EXPECT_TRUE(expected_type->Equals(actual_type)) << "When parsing {" << expected_type_pb_txt << "} " << " expected " << expected_type->DebugString() << " got " @@ -135,7 +150,7 @@ TEST(TypeProtos, ConvertsBasicTypesBetweenTypesAndProtos) { } } -TEST(TypeProtos, DoesNotConvertUnknownTypesToProtos) { +TEST_F(TypeProtos, DoesNotConvertUnknownTypesToProtos) { google::spanner::v1::Type actual_type_pb; EXPECT_EQ( absl::StatusCode::kInternal, @@ -150,7 +165,7 @@ TEST(ValueProtos, DoesNotConvertUnknownProtosToTypes) { TypeFromProto(unspecified_type_pb, &factory, &actual_type).code()); } -TEST(TypeProtos, DoesNotConvertProtoArrayTypeWithUnspecifiedElementType) { +TEST_F(TypeProtos, DoesNotConvertProtoArrayTypeWithUnspecifiedElementType) { zetasql::TypeFactory factory; const zetasql::Type* actual_type; EXPECT_EQ( diff --git a/frontend/handlers/BUILD b/frontend/handlers/BUILD index 469f8f67..96a680ca 100644 --- a/frontend/handlers/BUILD +++ b/frontend/handlers/BUILD @@ -32,7 +32,11 @@ cc_library( "//frontend/converters:time", "//frontend/entities:database", "//frontend/server:handler", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", "@com_google_googleapis//google/longrunning:longrunning_cc_grpc", "@com_google_googleapis//google/spanner/admin/database/v1:database_cc_grpc", "@com_google_protobuf//:cc_wkt_protos", diff --git a/frontend/handlers/databases.cc b/frontend/handlers/databases.cc index 51db78a8..cf095385 100644 --- a/frontend/handlers/databases.cc +++ b/frontend/handlers/databases.cc @@ -20,7 +20,12 @@ #include "google/longrunning/operations.pb.h" #include "google/protobuf/empty.pb.h" +#include "google/protobuf/timestamp.pb.h" #include "google/spanner/admin/database/v1/spanner_database_admin.pb.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "backend/database/database.h" #include "backend/schema/ddl/operations.pb.h" #include "backend/schema/parser/ddl_parser.h" diff --git a/frontend/handlers/partitions.cc b/frontend/handlers/partitions.cc index 084fc2f5..d09a79c8 100644 --- a/frontend/handlers/partitions.cc +++ b/frontend/handlers/partitions.cc @@ -14,6 +14,7 @@ // limitations under the License. // +#include #include #include "google/protobuf/struct.pb.h" @@ -32,7 +33,6 @@ #include "frontend/entities/session.h" #include "frontend/proto/partition_token.pb.h" #include "frontend/server/handler.h" -#include "absl/status/status.h" #include "zetasql/base/status_macros.h" namespace google { @@ -195,7 +195,8 @@ absl::Status PartitionQuery(RequestContext* ctx, ZETASQL_ASSIGN_OR_RETURN( backend::Query query, QueryFromProto(request->sql(), request->params(), request->param_types(), - txn->query_engine()->type_factory())); + txn->query_engine()->type_factory() + )); ZETASQL_RETURN_IF_ERROR(txn->query_engine()->IsPartitionable( query, backend::QueryContext{ diff --git a/tests/conformance/common/database_test_base.cc b/tests/conformance/common/database_test_base.cc index 83e50bbd..a39556c1 100644 --- a/tests/conformance/common/database_test_base.cc +++ b/tests/conformance/common/database_test_base.cc @@ -19,6 +19,7 @@ #include // NOLINT(build/c++11) #include #include +#include #include #include "absl/memory/memory.h" @@ -26,13 +27,11 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" +#include "google/cloud/spanner/admin/database_admin_client.h" #include "google/cloud/spanner/backoff_policy.h" #include "google/cloud/spanner/batch_dml_result.h" #include "google/cloud/spanner/commit_result.h" -#include "google/cloud/spanner/connection_options.h" #include "google/cloud/spanner/create_instance_request_builder.h" -#include "google/cloud/spanner/database_admin_connection.h" -#include "google/cloud/spanner/internal/database_admin_stub.h" #include "google/cloud/spanner/mutations.h" #include "google/cloud/spanner/polling_policy.h" #include "google/cloud/spanner/retry_policy.h" @@ -70,11 +69,23 @@ void DatabaseTest::SetUp() { absl::StrCat("test-database-", absl::ToUnixMicros(absl::Now()))); // Setup the database client. - database_client_ = std::make_unique( - cloud::spanner::MakeDatabaseAdminConnection( - *globals.connection_options, retry_policy->clone(), - backoff_policy->clone(), polling_policy->clone())); - ZETASQL_ASSERT_OK(ToUtilStatusOr(database_client_->CreateDatabase(*database_).get())); + auto connection_options = *globals.connection_options; + connection_options.set( + retry_policy->clone()); + connection_options.set( + backoff_policy->clone()); + connection_options.set( + polling_policy->clone()); + database_client_ = + std::make_unique( + cloud::spanner_admin::MakeDatabaseAdminConnection( + std::move(connection_options))); + ZETASQL_ASSERT_OK(ToUtilStatusOr( + database_client_ + ->CreateDatabase( + database_->instance().FullName(), + absl::StrCat("CREATE DATABASE `", database_->database_id(), "`")) + .get())); // Setup a client to interact with the database. client_ = std::make_unique( @@ -82,9 +93,9 @@ void DatabaseTest::SetUp() { *globals.connection_options)); // Setup stubs to access low-level API features not exposed by the C++ client. - std::shared_ptr channel = - grpc::CreateChannel(globals.connection_options->endpoint(), - globals.connection_options->credentials()); + std::shared_ptr channel = grpc::CreateChannel( + globals.connection_options->get(), + globals.connection_options->get()); spanner_stub_ = v1::Spanner::NewStub(channel); database_admin_stub_ = admin::database::v1::DatabaseAdmin::NewStub(channel); @@ -94,20 +105,29 @@ void DatabaseTest::SetUp() { ZETASQL_ASSERT_OK(SetUpDatabase()); } -void DatabaseTest::TearDown() { database_client_->DropDatabase(*database_); } +void DatabaseTest::TearDown() { + database_client_->DropDatabase(database_->FullName()); +} absl::Status DatabaseTest::ResetDatabase() { const ConformanceTestGlobals& globals = GetConformanceTestGlobals(); - ZETASQL_RETURN_IF_ERROR(ToUtilStatus(database_client_->DropDatabase(*database_))); + ZETASQL_RETURN_IF_ERROR( + ToUtilStatus(database_client_->DropDatabase(database_->FullName()))); database_ = std::make_unique( google::cloud::spanner::Instance(globals.project_id, globals.instance_id), absl::StrCat("test-database-", absl::ToUnixMicros(absl::Now()))); return ToUtilStatus( - database_client_->CreateDatabase(*database_).get().status()); + database_client_ + ->CreateDatabase( + database_->instance().FullName(), + absl::StrCat("CREATE DATABASE `", database_->database_id(), "`")) + .get() + .status()); } absl::Status DatabaseTest::SetSchema(const std::vector& schema) { - auto status_or = database_client_->UpdateDatabase(*database_, schema).get(); + auto status_or = + database_client_->UpdateDatabaseDdl(database_->FullName(), schema).get(); if (!status_or.ok()) { return ToUtilStatus(status_or.status()); } @@ -116,7 +136,8 @@ absl::Status DatabaseTest::SetSchema(const std::vector& schema) { absl::StatusOr DatabaseTest::UpdateSchema(const std::vector& schema) { - auto status_or = database_client_->UpdateDatabase(*database_, schema).get(); + auto status_or = + database_client_->UpdateDatabaseDdl(database_->FullName(), schema).get(); if (!status_or.ok()) { return ToUtilStatus(status_or.status()); } @@ -124,7 +145,7 @@ DatabaseTest::UpdateSchema(const std::vector& schema) { } absl::StatusOr> DatabaseTest::GetDatabaseDdl() const { - auto status_or = database_client_->GetDatabaseDdl(*database_); + auto status_or = database_client_->GetDatabaseDdl(database_->FullName()); if (!status_or.ok()) { return ToUtilStatus(status_or.status()); } diff --git a/tests/conformance/common/database_test_base.h b/tests/conformance/common/database_test_base.h index 11fc55aa..26760e15 100644 --- a/tests/conformance/common/database_test_base.h +++ b/tests/conformance/common/database_test_base.h @@ -33,9 +33,8 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/time/time.h" +#include "google/cloud/spanner/admin/database_admin_client.h" #include "google/cloud/spanner/client.h" -#include "google/cloud/spanner/database_admin_client.h" -#include "google/cloud/spanner/instance_admin_client.h" #include "google/cloud/spanner/keys.h" #include "google/cloud/spanner/mutations.h" #include "google/cloud/spanner/partition_options.h" @@ -682,7 +681,7 @@ class DatabaseTest : public ::testing::Test { std::unique_ptr database_; // The client used for the database admin api. - std::unique_ptr database_client_; + std::unique_ptr database_client_; // The client used for the spanner client api. std::unique_ptr client_; diff --git a/tests/conformance/common/environment.h b/tests/conformance/common/environment.h index 8d7773ef..7eff01d2 100644 --- a/tests/conformance/common/environment.h +++ b/tests/conformance/common/environment.h @@ -22,7 +22,7 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "google/cloud/spanner/connection_options.h" +#include "google/cloud/spanner/options.h" #include "google/cloud/status.h" #include "google/cloud/status_or.h" #include "absl/status/status.h" @@ -42,7 +42,7 @@ struct ConformanceTestGlobals { bool in_prod_env = false; // Client library options for connecting to the Cloud Spanner under test. - std::unique_ptr connection_options; + std::unique_ptr connection_options; }; // Returns the globals shared by all conformance tests. diff --git a/tests/conformance/data/schema_changes/check_constraint.test b/tests/conformance/data/schema_changes/check_constraint.test index 0542e231..9aa7df86 100644 --- a/tests/conformance/data/schema_changes/check_constraint.test +++ b/tests/conformance/data/schema_changes/check_constraint.test @@ -175,9 +175,10 @@ CREATE TABLE T ( CONSTRAINT _col_a_gt_zero CHECK(A > 0), ) PRIMARY KEY(A); -- -ERROR: .*name not valid: _col_a_gt_zero.* +ERROR:.* .*name not valid: _col_a_gt_zero.* == # Multiple table with check constraint of the same name. +# --regex CREATE TABLE T1 ( A INT64, CONSTRAINT a_gt_zero CHECK(A > 0), @@ -188,9 +189,10 @@ CREATE TABLE T2 ( CONSTRAINT a_gt_zero CHECK(A > 0), ) PRIMARY KEY(A); -- -ERROR: Duplicate name in schema: a_gt_zero. +ERROR:.* Duplicate name in schema: a_gt_zero. == # Constraint and table name conflict. +# --regex CREATE TABLE T1 ( A INT64, CONSTRAINT T2 CHECK(A > 0), @@ -201,26 +203,29 @@ CREATE TABLE T2 ( CONSTRAINT a_gt_zero CHECK(A > 0), ) PRIMARY KEY(A); -- -ERROR: Duplicate name in schema: T2. +ERROR:.* Duplicate name in schema: T2. == # Check constraint with const expression. +# --regex CREATE TABLE T ( A INT64, CONSTRAINT const_check CHECK(1 > 0), ) PRIMARY KEY(A); -- -ERROR: Check constraint `T`.`const_check` does not use any non generated column. Expression: '1 > 0'. A check constraint expression requires at least one non-generated column as dependency. +ERROR:.* Check constraint `T`.`const_check` does not use any non generated column. Expression: '1 > 0'. A check constraint expression requires at least one non-generated column as dependency. == # Check constraint with const expression with gen col. +# --regex CREATE TABLE T ( A INT64, B INT64 as (1) STORED, CONSTRAINT const_check CHECK(B > 0), ) PRIMARY KEY(A); -- -ERROR: Check constraint `T`.`const_check` does not use any non generated column. Expression: 'B > 0'. A check constraint expression requires at least one non-generated column as dependency. +ERROR:.* Check constraint `T`.`const_check` does not use any non generated column. Expression: 'B > 0'. A check constraint expression requires at least one non-generated column as dependency. == # Check constraint with const expression with two level gen col. +# --regex CREATE TABLE T ( A INT64, B INT64 as (1) STORED, @@ -228,9 +233,10 @@ CREATE TABLE T ( CONSTRAINT const_check CHECK(C > 0), ) PRIMARY KEY(A); -- -ERROR: Check constraint `T`.`const_check` does not use any non generated column. Expression: 'C > 0'. A check constraint expression requires at least one non-generated column as dependency. +ERROR:.* Check constraint `T`.`const_check` does not use any non generated column. Expression: 'C > 0'. A check constraint expression requires at least one non-generated column as dependency. == # Check constraint with const expression with two level gen col reverse order. +# --regex CREATE TABLE T ( A INT64, C INT64 AS (B) STORED, @@ -238,9 +244,10 @@ CREATE TABLE T ( CONSTRAINT const_check CHECK(C > 0), ) PRIMARY KEY(A); -- -ERROR: Check constraint `T`.`const_check` does not use any non generated column. Expression: 'C > 0'. A check constraint expression requires at least one non-generated column as dependency. +ERROR:.* Check constraint `T`.`const_check` does not use any non generated column. Expression: 'C > 0'. A check constraint expression requires at least one non-generated column as dependency. == # Check constraint with const expression with two level gen col reverse order by name. +# --regex CREATE TABLE T ( A INT64, C INT64 AS (1) STORED, @@ -248,17 +255,19 @@ CREATE TABLE T ( CONSTRAINT const_check CHECK(B > 0), ) PRIMARY KEY(A); -- -ERROR: Check constraint `T`.`const_check` does not use any non generated column. Expression: 'B > 0'. A check constraint expression requires at least one non-generated column as dependency. +ERROR:.* Check constraint `T`.`const_check` does not use any non generated column. Expression: 'B > 0'. A check constraint expression requires at least one non-generated column as dependency. == # Constraint expression invalid expression. +# --regex CREATE TABLE T ( A INT64, constraint a_is_not_zero CHECK(A B C), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'A B C' from check constraint 'a_is_not_zero' in table 'T': Syntax error: Expected end of input but got identifier "B" [at 1:3]\nA B C\n ^ +ERROR:.* Error parsing expression 'A B C' from check constraint 'a_is_not_zero' in table 'T': Syntax error: Expected end of input but got identifier "B" \[at 1:3]\nA B C\n \^ == # Constraint using column from another table. +# --regex CREATE TABLE T1 ( A1 INT64, ) PRIMARY KEY(A1); @@ -269,75 +278,84 @@ CREATE TABLE T2 ( check (A1 > 0), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'A1 > 0' from check constraint '' in table 'T2': Unrecognized name: A1 [at 1:1]\nA1 > 0\n^ +ERROR:.* Error parsing expression 'A1 > 0' from check constraint '' in table 'T2': Unrecognized name: A1 \[at 1:1]\nA1 > 0\n\^ == # Constraint with INT32 type. +# --regex CREATE TABLE T ( A INT64, check (CAST(1 as INT32)), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'CAST(1 as INT32)' from check constraint '' in table 'T': Type not found: INT32 [at 1:11]\nCAST(1 as INT32)\n ^ +ERROR:.* Error parsing expression 'CAST\(1 as INT32\)' from check constraint '' in table 'T': Type not found: INT32 \[at 1:11]\nCAST\(1 as INT32\)\n \^ == # Constraint with INT64 type. +# --regex CREATE TABLE T ( A INT64, check (CAST(1 as INT64)), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'CAST(1 as INT64)' from check constraint '' in table 'T': Expected type BOOL; found INT64 [at 1:1]\nCAST(1 as INT64)\n ^ +ERROR:.* Error parsing expression 'CAST\(1 as INT64\)' from check constraint '' in table 'T': Expected type BOOL; found INT64 \[at 1:1]\nCAST\(1 as INT64\)\n \^ == # Constraint with FLOAT type. +# --regex CREATE TABLE T ( A INT64, check (CAST(1 as FLOAT)), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'CAST(1 as FLOAT)' from check constraint '' in table 'T': Type not found: FLOAT [at 1:11]\nCAST(1 as FLOAT)\n ^ +ERROR:.* Error parsing expression 'CAST\(1 as FLOAT\)' from check constraint '' in table 'T': Type not found: FLOAT \[at 1:11]\nCAST\(1 as FLOAT\)\n \^ == # Constraint with FLOAT64 type. +# --regex CREATE TABLE T ( A INT64, check (CAST(1 as FLOAT64)), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'CAST(1 as FLOAT64)' from check constraint '' in table 'T': Expected type BOOL; found FLOAT64 [at 1:1]\nCAST(1 as FLOAT64)\n ^ +ERROR:.* Error parsing expression 'CAST\(1 as FLOAT64\)' from check constraint '' in table 'T': Expected type BOOL; found FLOAT64 \[at 1:1]\nCAST\(1 as FLOAT64\)\n \^ == # Constraint with STRING type. +# --regex CREATE TABLE T ( A INT64, check ("1 is gt 0"), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression '"1 is gt 0"' from check constraint '' in table 'T': Expected type BOOL; found STRING [at 1:1] "1 is gt 0" ^ +ERROR:.* Error parsing expression '"1 is gt 0"' from check constraint '' in table 'T': Expected type BOOL; found STRING \[at 1:1] "1 is gt 0" \^ == # Constraint with BYTES type. +# --regex CREATE TABLE T ( A INT64, check (CAST("1 is gt 0" as BYTES)), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'CAST("1 is gt 0" as BYTES)' from check constraint '' in table 'T': Expected type BOOL; found BYTES [at 1:1] CAST("1 is gt 0" as BYTES) ^ +ERROR:.* Error parsing expression 'CAST\("1 is gt 0" as BYTES\)' from check constraint '' in table 'T': Expected type BOOL; found BYTES \[at 1:1] CAST\("1 is gt 0" as BYTES\) \^ == # Constraint with TIMESTAMP type. +# --regex CREATE TABLE T ( A INT64, Ts TIMESTAMP, check (Ts), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'Ts' from check constraint '' in table 'T': Expected type BOOL; found TIMESTAMP [at 1:1] Ts ^ +ERROR:.* Error parsing expression 'Ts' from check constraint '' in table 'T': Expected type BOOL; found TIMESTAMP \[at 1:1] Ts \^ == # Constraint with DATE type. +# --regex CREATE TABLE T ( A INT64, Day DATE, check (Day), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'Day' from check constraint '' in table 'T': Expected type BOOL; found DATE [at 1:1] Day ^ +ERROR:.* Error parsing expression 'Day' from check constraint '' in table 'T': Expected type BOOL; found DATE \[at 1:1] Day \^ == # Constraint with non-scalar expression. +# --regex CREATE TABLE T1 ( A INT64, ) PRIMARY KEY(A); @@ -348,35 +366,39 @@ CREATE TABLE T2 ( constraint fk_t2_b_t1_a check (exists (select t1.A as a from T1 t1 where t1.A = B)), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'exists (select t1.A as a from T1 t1 where t1.A = B)' from check constraint 'fk_t2_b_t1_a' in table 'T2': Cannot use non-scalar expressions inside check constraints. +ERROR:.* Error parsing expression 'exists \(select t1.A as a from T1 t1 where t1.A = B\)' from check constraint 'fk_t2_b_t1_a' in table 'T2': Cannot use non-scalar expressions inside check constraints. == # Constraint with nested non-scalar expression. +# --regex CREATE TABLE T ( A INT64, CHECK (ARRAY_LENGTH(ARRAY(SELECT 1)) > A) ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'ARRAY_LENGTH(ARRAY(SELECT 1)) > A' from check constraint '' in table 'T': Cannot use non-scalar expressions inside check constraints. +ERROR:.* Error parsing expression 'ARRAY_LENGTH\(ARRAY\(SELECT 1\)\) > A' from check constraint '' in table 'T': Cannot use non-scalar expressions inside check constraints. == # Constraint with non-deterministic function. +# --regex CREATE TABLE T ( A INT64, B INT64, check (EXTRACT(YEAR from CURRENT_TIMESTAMP()) > 2018), ) PRIMARY KEY(A); -- -ERROR: Error parsing expression 'EXTRACT(YEAR from CURRENT_TIMESTAMP()) > 2018' from check constraint '' in table 'T': Expression is non-deterministic due to the use of non-determinstic function `CURRENT_TIMESTAMP`. Expression of check constraints must yield the same value for the same dependent column values. Non-deterministic functions inside the expressions are not allowed. +ERROR:.* Error parsing expression 'EXTRACT\(YEAR from CURRENT_TIMESTAMP\(\)\) > 2018' from check constraint '' in table 'T': Expression is non-deterministic due to the use of non-determinstic function `CURRENT_TIMESTAMP`. Expression of check constraints must yield the same value for the same dependent column values. Non-deterministic functions inside the expressions are not allowed. == # Check constraint depending on non-deterministic generated column. +# --regex CREATE TABLE T ( A INT64, B INT64 as (EXTRACT(YEAR from CURRENT_TIMESTAMP())) STORED, check (B > A), ) PRIMARY KEY(A); -- -ERROR: Error parsing the definition of generated column `T`.`B`: Expression is non-deterministic due to the use of non-determinstic function `CURRENT_TIMESTAMP`. Expression of stored generated columns must yield the same value for the same dependent column values. Non-deterministic functions inside the expressions are not allowed. +ERROR:.* Error parsing the definition of generated column `T`.`B`: Expression is non-deterministic due to the use of non-determinstic function `CURRENT_TIMESTAMP`. Expression of stored generated columns must yield the same value for the same dependent column values. Non-deterministic functions inside the expressions are not allowed. == # Check constraint depending on chained non-deterministic generated column. +# --regex CREATE TABLE T ( A INT64, B INT64 as (EXTRACT(YEAR from CURRENT_TIMESTAMP())), @@ -384,7 +406,7 @@ CREATE TABLE T ( check (C > A), ) PRIMARY KEY(A); -- -ERROR: Generated column `B` without the STORED attribute is not supported. +ERROR:.* Generated column `B` without the STORED attribute is not supported. == # Commit timestamp column not supported. # --regex @@ -394,9 +416,10 @@ CREATE TABLE T ( CHECK(EXTRACT(YEAR from B) > 2018) ) PRIMARY KEY(A); -- -ERROR: .*Column `B` has option commit_timestamp, which is not supported in check constraint. +ERROR:.* .*Column `B` has option commit_timestamp, which is not supported in check constraint. == # Column used by check constraint can not be changed to use commit_timestamp. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B TIMESTAMP, @@ -404,9 +427,10 @@ CREATE TABLE T ( ) PRIMARY KEY(A); ALTER TABLE T ALTER COLUMN B SET OPTIONS (allow_commit_timestamp = true); -- -ERROR: Column `B` has option commit_timestamp, which is not supported in check constraint. +ERROR:.* Column `B` has option commit_timestamp, which is not supported in check constraint. == # Add check constraint to existing table with duplicate name. +# --regex CREATE TABLE T ( A INT64, Value INT64, @@ -414,9 +438,10 @@ CREATE TABLE T ( ) PRIMARY KEY(A); ALTER TABLE T ADD CONSTRAINT value_gt_zero check(Value > 0); -- -ERROR: Duplicate name in schema: value_gt_zero. +ERROR:.* Duplicate name in schema: value_gt_zero. == # Add check constraint before CREATE TABLE. +# --regex ALTER TABLE T ADD CONSTRAINT value_gt_zero check(Value > 0); CREATE TABLE T ( A INT64, @@ -424,17 +449,19 @@ CREATE TABLE T ( CONSTRAINT value_gt_zero check(Value > 0) ) PRIMARY KEY(A); -- -ERROR: Table not found: T +ERROR:.* Table not found: T == # Add check constraint with const expression. +# --regex CREATE TABLE T ( A INT64, ) PRIMARY KEY(A); ALTER TABLE T ADD CONSTRAINT const_check check(1 > 0); -- -ERROR: Check constraint `T`.`const_check` does not use any non generated column. Expression: '1 > 0'. A check constraint expression requires at least one non-generated column as dependency. +ERROR:.* Check constraint `T`.`const_check` does not use any non generated column. Expression: '1 > 0'. A check constraint expression requires at least one non-generated column as dependency. == # Change the type of a column that is directly used by a check constraint. +# --regex CREATE TABLE T ( id INT64 NOT NULL, a STRING(MAX), @@ -442,9 +469,10 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN a BYTES(MAX); -- -ERROR: Cannot change the data type of column `a`, which is used by check constraint `a_gt_zero`. +ERROR:.* Cannot change the data type of column `a`, which is used by check constraint `a_gt_zero`. == # Change the type of a column that is indirectly used by a check constraint. +# --regex CREATE TABLE T ( id INT64 NOT NULL, a STRING(MAX), @@ -453,9 +481,10 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN a BYTES(MAX); -- -ERROR: Cannot change the data type of column `a`, which has a dependent stored generated column. +ERROR:.* Cannot change the data type of column `a`, which has a dependent stored generated column. == # Change the subtype of an array column that is used by a check constraint. +# --regex CREATE TABLE T ( id INT64 NOT NULL, a ARRAY, @@ -463,9 +492,10 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN a ARRAY; -- -ERROR: Cannot change the data type of column `a`, which is used by check constraint `a_length_gt_zero`. +ERROR:.* Cannot change the data type of column `a`, which is used by check constraint `a_length_gt_zero`. == # Drop a column that is directly used by a check constraint. +# --regex CREATE TABLE T ( id INT64 NOT NULL, a INT64, @@ -473,9 +503,10 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T DROP COLUMN a; -- -ERROR: Cannot drop column `a` from table `T` because it is referenced by check constraint `a_gt_zero`. +ERROR:.* Cannot drop column `a` from table `T` because it is referenced by check constraint `a_gt_zero`. == # Drop a column that is indirectly used by a check constraint via stored generated columm. +# --regex CREATE TABLE T ( id INT64 NOT NULL, a INT64, @@ -484,12 +515,13 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T DROP COLUMN a; -- -ERROR: Cannot drop column `a` from table `T` because it is referenced by generated column `b`. +ERROR:.* Cannot drop column `a` from table `T` because it is referenced by generated column `b`. == # Constraint with the same name as the defining table. +# --regex CREATE TABLE a ( b BOOL, CONSTRAINT a CHECK (b) ) PRIMARY KEY (); -- -ERROR: Duplicate name in schema: a. +ERROR:.* Duplicate name in schema: a. diff --git a/tests/conformance/data/schema_changes/column_default_values.test b/tests/conformance/data/schema_changes/column_default_values.test index 16b59869..7f0897b8 100644 --- a/tests/conformance/data/schema_changes/column_default_values.test +++ b/tests/conformance/data/schema_changes/column_default_values.test @@ -326,21 +326,23 @@ CREATE TABLE T ( Cannot use non-scalar expressions inside column default == # allow_commit_timestamp not allowed on column with default value. +# --regex CREATE TABLE T( id INT64, ts TIMESTAMP DEFAULT (CURRENT_TIMESTAMP()) OPTIONS (allow_commit_timestamp = true) ) PRIMARY KEY(id); -- -ERROR: Cannot use commit timestamp column `ts` as a column with default value. +ERROR:.* Cannot use commit timestamp column `ts` as a column with default value. == # SET DEFAULT: allow_commit_timestamp not allowed on column with default value. +# --regex CREATE TABLE T( id INT64, ts TIMESTAMP OPTIONS (allow_commit_timestamp = true) ) PRIMARY KEY(id); ALTER TABLE T ALTER ts SET DEFAULT (CURRENT_TIMESTAMP()); -- -ERROR: Cannot use commit timestamp column `ts` as a column with default value. +ERROR:.* Cannot use commit timestamp column `ts` as a column with default value. == # PENDING_COMMIT_TIMESTAMP not allowed on column with default value. CREATE TABLE T ( diff --git a/tests/conformance/data/schema_changes/combined.test b/tests/conformance/data/schema_changes/combined.test index db2e6b5f..04bc90fb 100644 --- a/tests/conformance/data/schema_changes/combined.test +++ b/tests/conformance/data/schema_changes/combined.test @@ -1,4 +1,5 @@ # Duplicate table name. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Users ( @@ -6,9 +7,10 @@ CREATE TABLE Users ( CREATE TABLE users ( ) PRIMARY KEY(); -- -ERROR: Duplicate name in schema: Users. +ERROR:.* Duplicate name in schema: Users. == # Index names are in the same namespace. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), @@ -19,9 +21,10 @@ CREATE TABLE UsersByName ( CREATE TABLE usersbyname ( ) PRIMARY KEY(); -- -ERROR: Duplicate name in schema: UsersByName. +ERROR:.* Duplicate name in schema: UsersByName. == # NOT NULL constraint cannot be dropped because it affects indexing of nulls +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), @@ -35,23 +38,26 @@ CREATE TABLE Albums ( CREATE INDEX AlbumsByName ON Albums(AlbumName); ALTER TABLE Albums ALTER COLUMN AlbumName STRING(MAX); -- -ERROR: Changing NOT NULL constraints on column AlbumName is not allowed because it affects index AlbumsByName. +ERROR:.* Changing NOT NULL constraints on column AlbumName is not allowed because it affects index AlbumsByName. == # Interleave within nonexistent table. +# --regex CREATE TABLE Albums ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Users ON DELETE CASCADE; -- -ERROR: Table not found: Users +ERROR:.* Table not found: Users == # Interleave within self, which counts as a nonexistent table. +# --regex CREATE TABLE Albums ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Albums ON DELETE CASCADE; -- -ERROR: Table not found: Albums +ERROR:.* Table not found: Albums == # Duplicate column name. +# --regex CREATE TABLE Users ( UserName STRING(MAX), UserName STRING(MAX), @@ -61,14 +67,14 @@ CREATE TABLE Users ( username STRING(MAX), ) PRIMARY KEY(); -- -ERROR: Duplicate column name Users.UserName. +ERROR:.* Duplicate column name Users.UserName. == # Primary key references a nonexistent column. # --regex CREATE TABLE Users ( ) PRIMARY KEY(UserId); -- -ERROR: [Tt]able Users references nonexistent key column UserId. +ERROR:.* [Tt]able Users references nonexistent key column UserId. == # Primary key references a column with incorrect case. # --regex @@ -76,7 +82,7 @@ CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(userid); -- -ERROR: [Tt]able Users references nonexistent key column userid. +ERROR:.* [Tt]able Users references nonexistent key column userid. == # Primary key references a column twice. # --regex @@ -84,16 +90,18 @@ CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId, UserId); -- -ERROR: [Tt]able Users references key column UserId more than once. +ERROR:.* [Tt]able Users references key column UserId more than once. == # Primary key references an ARRAY column. +# --regex CREATE TABLE Users ( UserIds ARRAY NOT NULL, ) PRIMARY KEY(UserIds); -- -ERROR: Column Users.UserIds has type ARRAY, but is part of the primary key. +ERROR:.* Column Users.UserIds has type ARRAY, but is part of the primary key. == # Interleaved table does not reference parent key column. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); @@ -101,9 +109,10 @@ CREATE TABLE Albums ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Users ON DELETE CASCADE; -- -ERROR: Table Albums does not reference parent key column UserId. +ERROR:.* Table Albums does not reference parent key column UserId. == # Interleaved table references parent key column at incorrect position. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); @@ -113,9 +122,10 @@ CREATE TABLE Albums ( ) PRIMARY KEY(AlbumId, UserId), INTERLEAVE IN PARENT Users ON DELETE CASCADE; -- -ERROR: Table Albums references parent key column UserId at incorrect position 1. +ERROR:.* Table Albums references parent key column UserId at incorrect position 1. == # Interleaved table references parent key column with incorrect sort order. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); @@ -124,9 +134,10 @@ CREATE TABLE Albums ( ) PRIMARY KEY(UserId DESC), INTERLEAVE IN PARENT Users ON DELETE CASCADE; -- -ERROR: Table Albums references parent key column UserId with incorrect order ASC. +ERROR:.* Table Albums references parent key column UserId with incorrect order ASC. == # Interleaved table references parent key column with incorrect length. +# --regex CREATE TABLE Users ( UserName STRING(MAX) NOT NULL, ) PRIMARY KEY(UserName); @@ -135,7 +146,7 @@ CREATE TABLE Albums ( ) PRIMARY KEY(UserName), INTERLEAVE IN PARENT Users ON DELETE CASCADE; -- -ERROR: Table Albums references parent key column UserName with incorrect length 42 (should be MAX). +ERROR:.* Table Albums references parent key column UserName with incorrect length 42 \(should be MAX\). == # Column of type DOUBLE listed as key of a directory table. CREATE TABLE Users ( @@ -147,20 +158,23 @@ CREATE TABLE Users ( ) PRIMARY KEY(UserId); == # Column has invalid length. +# --regex CREATE TABLE Users ( UserName STRING(0), ) PRIMARY KEY(); -- -ERROR: Bad length for column Users.UserName: 0 : Allowed length range: [1, 2621440]. +ERROR:.* Bad length for column Users.UserName: 0 : Allowed length range: \[1, 2621440]. == # ARRAY column has invalid length. +# --regex CREATE TABLE Users ( UserName ARRAY, ) PRIMARY KEY(); -- -ERROR: Bad length for column Users.UserName: 400000000 : Allowed length range: [1, 2621440]. +ERROR:.* Bad length for column Users.UserName: 400000000 : Allowed length range: \[1, 2621440]. == # Table has too many keys. +# --regex CREATE TABLE Users ( UserId1 INT64 NOT NULL, UserId2 INT64 NOT NULL, @@ -205,9 +219,10 @@ CREATE TABLE Photos ( ) PRIMARY KEY(UserId1, UserId2, UserId3, UserId4, UserId5, UserId6, AlbumId1, AlbumId2, AlbumId3, AlbumId4, AlbumId5, AlbumId6, PhotoId1, PhotoId2, PhotoId3, PhotoId4, PhotoId5), INTERLEAVE IN PARENT Albums ON DELETE CASCADE; -- -ERROR: Table Photos has too many keys (17); the limit is 16. +ERROR:.* Table Photos has too many keys \(17\); the limit is 16. == # Third-level table has no columns. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -217,7 +232,7 @@ CREATE TABLE Photos ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Albums ON DELETE CASCADE; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Non-primary key column is NOT NULL for a directory table. CREATE TABLE Users ( @@ -229,24 +244,27 @@ CREATE TABLE Users ( ) PRIMARY KEY(); == # Options invalid for the column type +# --regex CREATE TABLE Users ( UserName STRING(MAX) OPTIONS ( allow_commit_timestamp = true ), ) PRIMARY KEY(); -- -ERROR: Column Users.UserName has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column Users.UserName has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Options invalid for the column type if allowed on TIMESTAMP. +# --regex CREATE TABLE Users ( UserName STRING(MAX) OPTIONS ( allow_commit_timestamp = true ), ) PRIMARY KEY(); -- -ERROR: Column Users.UserName has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column Users.UserName has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Child table must match parent key commit timestamp settings #1 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL OPTIONS ( allow_commit_timestamp = true @@ -257,9 +275,10 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Child table must match parent key commit timestamp settings #2 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL OPTIONS ( allow_commit_timestamp = true @@ -272,9 +291,10 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Child table must match parent key commit timestamp settings #3 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL, ) PRIMARY KEY(Timestamp); @@ -285,9 +305,10 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column B.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column B.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Child table must match parent key commit timestamp settings #4 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL OPTIONS ( allow_commit_timestamp = false @@ -300,9 +321,10 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Duplicate index name. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), @@ -311,18 +333,20 @@ CREATE NULL_FILTERED INDEX UsersByName ON Users(UserName); CREATE NULL_FILTERED INDEX UsersByName ON Users(UserName); CREATE NULL_FILTERED INDEX usersbyname ON Users(UserName); -- -ERROR: Duplicate name in schema: UsersByName. +ERROR:.* Duplicate name in schema: UsersByName. == # Table names are in the same namespace. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), ) PRIMARY KEY(UserId); CREATE NULL_FILTERED INDEX Users ON Users(UserName); -- -ERROR: Duplicate name in schema: Users. +ERROR:.* Duplicate name in schema: Users. == # Index specifies nonexistent table for interleaving. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); @@ -334,9 +358,10 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; CREATE NULL_FILTERED INDEX AlbumsByName ON Albums(UserId, AlbumName), INTERLEAVE IN DoesNotExist; -- -ERROR: Cannot interleave index AlbumsByName within nonexistent table DoesNotExist. +ERROR:.* Cannot interleave index AlbumsByName within nonexistent table DoesNotExist. == # Ordering of a parent key component for an interleaved index doesn't match. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); @@ -348,18 +373,20 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; CREATE NULL_FILTERED INDEX AlbumsByName ON Albums(UserId DESC, AlbumName), INTERLEAVE IN Users; -- -ERROR: Index AlbumsByName references parent key column UserId with incorrect order ASC. +ERROR:.* Index AlbumsByName references parent key column UserId with incorrect order ASC. == # Index does not specify any key columns. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); CREATE NULL_FILTERED INDEX UsersByNothing ON Users(); -- -ERROR: Index UsersByNothing does not specify any key columns. +ERROR:.* Index UsersByNothing does not specify any key columns. == # Index has too many keys. Note the total number of index keys includes the # keys of the table being indexed. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserId2 INT64 NOT NULL, @@ -383,26 +410,29 @@ CREATE TABLE Users ( ) PRIMARY KEY(UserId, UserId2); CREATE NULL_FILTERED INDEX UsersByData ON Users(Data1, Data2, UserId, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, Data13, Data14, Data15); -- -ERROR: Index UsersByData has too many keys (17); the limit is 16. +ERROR:.* Index UsersByData has too many keys \(17\); the limit is 16. == # Index specifies nonexistent key column. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); CREATE NULL_FILTERED INDEX UsersByName ON Users(UserName); -- -ERROR: Index UsersByName specifies key column UserName which does not exist in the index's base table. +ERROR:.* Index UsersByName specifies key column UserName which does not exist in the index's base table. == # Index specifies key column twice. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), ) PRIMARY KEY(UserId); CREATE NULL_FILTERED INDEX UsersByName ON Users(UserName, UserName); -- -ERROR: Index UsersByName specifies key column UserName twice. +ERROR:.* Index UsersByName specifies key column UserName twice. == # Index specifies keys that are not a prefix of the interleaved table. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); @@ -414,27 +444,30 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; CREATE NULL_FILTERED INDEX AlbumsByName ON Albums(AlbumName), INTERLEAVE IN Users; -- -ERROR: Index AlbumsByName does not reference index parent key column UserId. +ERROR:.* Index AlbumsByName does not reference index parent key column UserId. == # An index on an ARRAY without "DISTINCT_ARRAY_ELEMENT" is an error. +# --regex CREATE TABLE Root ( user_id INT64 NOT NULL, vals ARRAY, ) PRIMARY KEY(user_id); CREATE NULL_FILTERED INDEX Index1 ON Root(vals); -- -ERROR: Cannot reference ARRAY vals in the creation of index Index1. +ERROR:.* Cannot reference ARRAY vals in the creation of index Index1. == # Bad index name because index table collides with index directory name. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), ) PRIMARY KEY(UserId); CREATE NULL_FILTERED INDEX Dir_BadIndexName ON Users(UserName); -- -ERROR: Index name not valid: Dir_BadIndexName. +ERROR:.* Index name not valid: Dir_BadIndexName. == # Can't drop a table with interleaved tables. +# --regex DROP TABLE DoesNotExist; CREATE TABLE Users ( ) PRIMARY KEY(); @@ -447,9 +480,10 @@ CREATE TABLE Photos ( INTERLEAVE IN PARENT Albums ON DELETE CASCADE; DROP TABLE Albums; -- -ERROR: Table not found: DoesNotExist +ERROR:.* Table not found: DoesNotExist == # Can't drop a table with an index. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -460,8 +494,9 @@ CREATE TABLE Albums ( CREATE NULL_FILTERED INDEX AlbumsByName ON Albums(AlbumName); DROP TABLE Albums; -- -ERROR: Cannot drop table Albums with indices: AlbumsByName. +ERROR:.* Cannot drop table Albums with indices: AlbumsByName. == +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -477,26 +512,29 @@ CREATE TABLE Photos ( CREATE NULL_FILTERED INDEX PhotosByName ON Photos(AlbumId, PhotoName), INTERLEAVE IN Albums; DROP TABLE Albums; -- -ERROR: Cannot drop table Albums with interleaved tables: Photos. +ERROR:.* Cannot drop table Albums with interleaved tables: Photos. == # Duplicate column name for new column. +# --regex CREATE TABLE Users ( UserName STRING(MAX), ) PRIMARY KEY(); ALTER TABLE Users ADD COLUMN UserName STRING(MAX); ALTER TABLE Users ADD COLUMN username STRING(MAX); -- -ERROR: Duplicate column name Users.UserName. +ERROR:.* Duplicate column name Users.UserName. == # Make sure two added columns also fail. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); ALTER TABLE Users ADD COLUMN UserName STRING(MAX); ALTER TABLE Users ADD COLUMN UserName STRING(MAX); -- -ERROR: Duplicate column name Users.UserName. +ERROR:.* Duplicate column name Users.UserName. == # Duplicate column name for new column (interleave alias version). +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -505,39 +543,44 @@ CREATE TABLE Albums ( ALTER TABLE Users ADD COLUMN albums STRING(MAX); ALTER TABLE Users ADD COLUMN ALBums STRING(MAX); -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # New column is NOT NULL. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); ALTER TABLE Users ADD COLUMN UserName STRING(MAX) NOT NULL; -- -ERROR: Cannot add NOT NULL column Users.UserName to existing table Users. +ERROR:.* Cannot add NOT NULL column Users.UserName to existing table Users. == # New column has invalid length. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); ALTER TABLE Users ADD COLUMN UserName STRING(0); -- -ERROR: Bad length for column Users.UserName: 0 : Allowed length range: [1, 2621440]. +ERROR:.* Bad length for column Users.UserName: 0 : Allowed length range: \[1, 2621440]. == # Can't drop columns that don't exist. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); ALTER TABLE Users DROP COLUMN DoesNotExist; -- -ERROR: Column not found in table Users: DoesNotExist +ERROR:.* Column not found in table Users: DoesNotExist == # Can't drop key columns. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); ALTER TABLE Users DROP COLUMN UserId; -- -ERROR: Cannot drop key column UserId from table Users. +ERROR:.* Cannot drop key column UserId from table Users. == # Can't drop key columns from non-directory tables, either. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -546,9 +589,10 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; ALTER TABLE Albums DROP COLUMN AlbumId; -- -ERROR: Cannot drop key column AlbumId from table Albums. +ERROR:.* Cannot drop key column AlbumId from table Albums. == # Can't drop columns used as index keys. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), @@ -556,39 +600,43 @@ CREATE TABLE Users ( CREATE NULL_FILTERED INDEX UsersByName ON Users(UserName); ALTER TABLE Users DROP COLUMN UserName; -- -ERROR: Cannot drop column UserName from table Users because it is used by index UsersByName. +ERROR:.* Cannot drop column UserName from table Users because it is used by index UsersByName. == # Can't alter columns that don't exist. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); ALTER TABLE Users ALTER COLUMN DoesNotExist STRING(MAX); -- -ERROR: Column not found in table Users: DoesNotExist +ERROR:.* Column not found in table Users: DoesNotExist == # Altered primary key column is not NOT NULL. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); ALTER TABLE Users ALTER COLUMN UserId INT64; -- -ERROR: Cannot change key column Users.UserId. +ERROR:.* Cannot change key column Users.UserId. == # Altered column has invalid length. +# --regex CREATE TABLE Users ( UserName STRING(40), ) PRIMARY KEY(); ALTER TABLE Users ALTER COLUMN UserName STRING(400000000); -- -ERROR: Bad length for column Users.UserName: 400000000 : Allowed length range: [1, 2621440]. +ERROR:.* Bad length for column Users.UserName: 400000000 : Allowed length range: \[1, 2621440]. == # Remove NOT NULL from key. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, ) PRIMARY KEY(UserId); ALTER TABLE Users ALTER COLUMN UserId INT64; -- -ERROR: Cannot change key column Users.UserId. +ERROR:.* Cannot change key column Users.UserId. == # Arrays: decrease inner length of column. CREATE TABLE Users ( @@ -632,20 +680,22 @@ CREATE TABLE Users ( ) PRIMARY KEY(); == # SET ON DELETE requires an interleaved table. +# --regex CREATE TABLE Users ( UserId STRING(MAX) NOT NULL, ) PRIMARY KEY(UserId); ALTER TABLE Users SET ON DELETE CASCADE; -- -ERROR: Cannot SET ON DELETE on table Users that does not have an INTERLEAVE clause. +ERROR:.* Cannot SET ON DELETE on table Users that does not have an INTERLEAVE clause. == # Even an implicitly-interleaved table is insufficient. +# --regex CREATE TABLE Users ( UserId STRING(MAX) NOT NULL, ) PRIMARY KEY(UserId); ALTER TABLE Users SET ON DELETE CASCADE; -- -ERROR: Cannot SET ON DELETE on table Users that does not have an INTERLEAVE clause. +ERROR:.* Cannot SET ON DELETE on table Users that does not have an INTERLEAVE clause. == # Test that the long-running schema changes do not work for arrays. # Arrays: Cannot add NOT NULL. @@ -679,33 +729,37 @@ CREATE TABLE T ( ) PRIMARY KEY(); == # Attempt to name a secondary index PRIMARY_KEY. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), ) PRIMARY KEY(UserId); CREATE INDEX PRIMARY_KEY ON Users(UserName); -- -ERROR: Cannot use reserved name PRIMARY_KEY for a secondary index +ERROR:.* Cannot use reserved name PRIMARY_KEY for .* == # Attempt to name a secondary index Primary_Key. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), ) PRIMARY KEY(UserId); CREATE INDEX Primary_Key ON Users(UserName); -- -ERROR: Cannot use reserved name PRIMARY_KEY for a secondary index +ERROR:.* Cannot use reserved name PRIMARY_KEY for .* == # Attempt to make a nullable primary key column not null. +# --regex CREATE TABLE Users ( UserId INT64, UserName STRING(MAX), ) PRIMARY KEY(UserId); ALTER TABLE Users ALTER COLUMN UserId INT64 NOT NULL; -- -ERROR: Cannot change key column Users.UserId. +ERROR:.* Cannot change key column Users.UserId. == # Attempt to make a nullable non-key column with an index not null. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), @@ -713,18 +767,20 @@ CREATE TABLE Users ( CREATE INDEX UsersByUserName ON Users(UserName); ALTER TABLE Users ALTER COLUMN UserName STRING(MAX) NOT NULL; -- -ERROR: Changing NOT NULL constraints on column UserName is not allowed because it affects index UsersByUserName. +ERROR:.* Changing NOT NULL constraints on column UserName is not allowed because it affects index UsersByUserName. == # Attempt to make a nullable primary key column not null. +# --regex CREATE TABLE Users ( UserId INT64, UserName STRING(MAX), ) PRIMARY KEY(UserId); ALTER TABLE Users ALTER COLUMN UserId INT64 NOT NULL; -- -ERROR: Cannot change key column Users.UserId. +ERROR:.* Cannot change key column Users.UserId. == # Attempt to make a nullable non-key column with an index not null. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL, UserName STRING(MAX), @@ -732,7 +788,7 @@ CREATE TABLE Users ( CREATE INDEX UsersByUserName ON Users(UserName); ALTER TABLE Users ALTER COLUMN UserName STRING(MAX) NOT NULL; -- -ERROR: Changing NOT NULL constraints on column UserName is not allowed because it affects index UsersByUserName. +ERROR:.* Changing NOT NULL constraints on column UserName is not allowed because it affects index UsersByUserName. == # Attempt to make reduce the size of an ARRAY subtype. CREATE TABLE Users ( @@ -747,6 +803,7 @@ CREATE TABLE Users ( ) PRIMARY KEY(UserId); == # Alter a directory table that is tentatively being dropped. +# --regex CREATE TABLE dir1 ( k INT64 NOT NULL, v STRING(1), @@ -754,9 +811,10 @@ CREATE TABLE dir1 ( DROP TABLE dir1; ALTER TABLE dir1 ADD COLUMN v2 STRING(MAX); -- -ERROR: Table not found: dir1 +ERROR:.* Table not found: dir1 == # Alter a column of a directory table that is tentatively being dropped. +# --regex CREATE TABLE dir1 ( k INT64 NOT NULL, v STRING(1), @@ -764,9 +822,10 @@ CREATE TABLE dir1 ( DROP TABLE dir1; ALTER TABLE dir1 ALTER COLUMN v STRING(2); -- -ERROR: Table not found: dir1 +ERROR:.* Table not found: dir1 == # Create an index on a directory table that is tentatively being dropped. +# --regex CREATE TABLE dir1 ( k INT64 NOT NULL, v STRING(1), @@ -774,9 +833,10 @@ CREATE TABLE dir1 ( DROP TABLE dir1; CREATE INDEX dir1IndexOnC ON dir1(v); -- -ERROR: Table not found: dir1 +ERROR:.* Table not found: dir1 == # Create interleaved table in directory table that is tentatively being dropped. +# --regex CREATE TABLE dir1 ( k INT64 NOT NULL, v STRING(1), @@ -788,7 +848,7 @@ CREATE TABLE tbl ( ) PRIMARY KEY(k), INTERLEAVE IN PARENT dir1 ON DELETE CASCADE; -- -ERROR: Table not found: dir1 +ERROR:.* Table not found: dir1 == # Directory table with two non-key columns. CREATE TABLE Users ( @@ -848,13 +908,14 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; == # Interleaved table with no columns. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Users ON DELETE CASCADE; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Interleaved table with key and non-key columns. CREATE TABLE Users ( @@ -880,6 +941,7 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; == # Third-level interleaved table. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -890,7 +952,7 @@ CREATE TABLE Photos ( ) PRIMARY KEY(PhotoId), INTERLEAVE IN PARENT Albums ON DELETE CASCADE; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Date columns. CREATE TABLE T ( @@ -1038,6 +1100,7 @@ CREATE TABLE Albums ( CREATE NULL_FILTERED INDEX AlbumsByUser ON Albums(UserId); == # Child table matches parent key commit timestamp settings #1 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL OPTIONS ( allow_commit_timestamp = true @@ -1050,9 +1113,10 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Child table matches parent key commit timestamp settings #2 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL OPTIONS ( allow_commit_timestamp = false @@ -1065,9 +1129,10 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Child table matches parent key commit timestamp settings #3 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL, ) PRIMARY KEY(Timestamp); @@ -1078,9 +1143,10 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column B.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column B.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == # Child table matches parent key commit timestamp settings #4 +# --regex CREATE TABLE A ( Timestamp INT64 NOT NULL OPTIONS ( allow_commit_timestamp = false @@ -1091,7 +1157,7 @@ CREATE TABLE B ( ) PRIMARY KEY(Timestamp), INTERLEAVE IN PARENT A ON DELETE CASCADE; -- -ERROR: Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. +ERROR:.* Column A.Timestamp has invalid allow_commit_timestamp option. Option only allowed on TIMESTAMP columns. == CREATE TABLE T( A INT64, @@ -1107,6 +1173,7 @@ CREATE TABLE T ( ) PRIMARY KEY(A); == # Basic drop table. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -1114,7 +1181,7 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; DROP TABLE Albums; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Basic drop index. CREATE TABLE Users ( @@ -1236,33 +1303,37 @@ CREATE TABLE Users ( ) PRIMARY KEY(UserId); == # Interleaved table with implicit ON DELETE NO ACTION. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Users ON DELETE NO ACTION; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Interleaved table with explicit ON DELETE NO ACTION. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Users ON DELETE NO ACTION; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Interleaved table with ON DELETE NO ACTION allowed outside strict mode. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( ) PRIMARY KEY(), INTERLEAVE IN PARENT Users ON DELETE NO ACTION; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Interleaved table altered to ON DELETE NO ACTION. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -1270,7 +1341,7 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; ALTER TABLE Albums SET ON DELETE NO ACTION; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Attempt to make a nullable column not null. CREATE TABLE Users ( @@ -1297,6 +1368,7 @@ CREATE TABLE Users ( ) PRIMARY KEY(UserId); == # Interleaved table altered to ON DELETE CASCADE. No-op, but legal. +# --regex CREATE TABLE Users ( ) PRIMARY KEY(); CREATE TABLE Albums ( @@ -1304,7 +1376,7 @@ CREATE TABLE Albums ( INTERLEAVE IN PARENT Users ON DELETE CASCADE; ALTER TABLE Albums SET ON DELETE CASCADE; -- -ERROR: Table Albums adds no columns and is not a top level table. +ERROR:.* Table Albums adds no columns and is not a top level table. == # Check constraint tests for async replication # Create table without check constraint as reference. @@ -1326,13 +1398,14 @@ CREATE TABLE T ( CreatedAt TIMESTAMP, ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); == +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); ALTER TABLE T ALTER COLUMN CreatedAt INT64; -- -ERROR: ROW DELETION POLICY will break if drop/alter column named CreatedAt in table T. Row Deletion Policy must be set on column of type TIMESTAMP. +ERROR:.* ROW DELETION POLICY will break if drop/alter column named CreatedAt in table T. Row Deletion Policy must be set on column of type TIMESTAMP. == CREATE TABLE T ( Key INT64, @@ -1377,12 +1450,13 @@ CREATE TABLE T ( ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); == # Column is not timestamp +# --regex CREATE TABLE T ( Key INT64, CreatedAt INT64, ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); -- -ERROR: Cannot create ROW DELETION POLICY because column CreatedAt in table T is not of type TIMESTAMP. +ERROR:.* Cannot create ROW DELETION POLICY because column CreatedAt in table T is not of type TIMESTAMP. == CREATE TABLE T ( Key INT64, @@ -1407,30 +1481,33 @@ CREATE TABLE T ( ) PRIMARY KEY(Key); == # Policy already exist +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); ALTER TABLE T ADD ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); -- -ERROR: Cannot create ROW DELETION POLICY because there is already one on column named CreatedAt in table T. +ERROR:.* Cannot create ROW DELETION POLICY because there is already one on column named CreatedAt in table T. == # Column does not exist +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(ModifiedAt, INTERVAL 7 DAY)); -- -ERROR: Cannot create ROW DELETION POLICY because there is no column named ModifiedAt in table T. +ERROR:.* Cannot create ROW DELETION POLICY because there is no column named ModifiedAt in table T. == # Column does not exist +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, ) PRIMARY KEY(Key); ALTER TABLE T ADD ROW DELETION POLICY (OLDER_THAN(ModifiedAt, INTERVAL 7 DAY)); -- -ERROR: Cannot create ROW DELETION POLICY because there is no column named ModifiedAt in table T. +ERROR:.* Cannot create ROW DELETION POLICY because there is no column named ModifiedAt in table T. == CREATE TABLE T ( Key INT64, @@ -1444,33 +1521,37 @@ CREATE TABLE T ( ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); == # Policy does not exist for replace +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, ) PRIMARY KEY(Key); ALTER TABLE T REPLACE ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); -- -ERROR: ROW DELETION POLICY does not exist on table T. +ERROR:.* ROW DELETION POLICY does not exist on table T. == # Policy does not exist for drop +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, ) PRIMARY KEY(Key); ALTER TABLE T DROP ROW DELETION POLICY; -- -ERROR: ROW DELETION POLICY does not exist on table T. +ERROR:.* ROW DELETION POLICY does not exist on table T. == # Policy will break +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, ) PRIMARY KEY(Key), ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 1 DAY)); ALTER TABLE T DROP COLUMN CreatedAt -- -ERROR: ROW DELETION POLICY will break if drop/alter column named CreatedAt in table T. Row Deletion Policy must be set on column of type TIMESTAMP. +ERROR:.* ROW DELETION POLICY will break if drop/alter column named CreatedAt in table T. Row Deletion Policy must be set on column of type TIMESTAMP. == # Child must have delete cascade +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, @@ -1482,9 +1563,10 @@ CREATE TABLE U ( ) PRIMARY KEY(Key), INTERLEAVE IN PARENT T ON DELETE NO ACTION; ALTER TABLE T ADD ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); -- -ERROR: Cannot create row deletion policy on T because there is a descendant Table U with ON DELETE NO ACTION. +ERROR:.* Cannot create row deletion policy on T because there is a descendant Table U with ON DELETE NO ACTION. == # Grandchild must have delete cascade +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, @@ -1501,9 +1583,10 @@ CREATE TABLE V ( ) PRIMARY KEY(Key), INTERLEAVE IN PARENT U ON DELETE NO ACTION; ALTER TABLE T ADD ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); -- -ERROR: Cannot create row deletion policy on T because there is a descendant Table V with ON DELETE NO ACTION. +ERROR:.* Cannot create row deletion policy on T because there is a descendant Table V with ON DELETE NO ACTION. == # Policy on ancestor +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, @@ -1514,9 +1597,10 @@ CREATE TABLE U ( Data INT64, ) PRIMARY KEY(Key), INTERLEAVE IN PARENT T ON DELETE NO ACTION; -- -ERROR: Cannot create or alter table U with ON DELETE NO ACTION because there is a row deletion policy on ancestor table T. +ERROR:.* Cannot create or alter table U with ON DELETE NO ACTION because there is a row deletion policy on ancestor table T. == # Policy on ancestor +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, @@ -1528,9 +1612,10 @@ CREATE TABLE U ( ) PRIMARY KEY(Key), INTERLEAVE IN PARENT T ON DELETE CASCADE; ALTER TABLE U SET ON DELETE NO ACTION; -- -ERROR: Cannot create or alter table U with ON DELETE NO ACTION because there is a row deletion policy on ancestor table T. +ERROR:.* Cannot create or alter table U with ON DELETE NO ACTION because there is a row deletion policy on ancestor table T. == # Policy on foreign key +# --regex CREATE TABLE T ( Key INT64, CreatedAt TIMESTAMP, @@ -1542,7 +1627,7 @@ CREATE TABLE U ( ) PRIMARY KEY(MyKey); ALTER TABLE T ADD ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 7 DAY)); -- -ERROR: Cannot add a row deletion policy to table `T`. It is referenced by one or more foreign keys: `FK_Key`. +ERROR:.* Cannot add a row deletion policy to table `T`. It is referenced by one or more foreign keys: `FK_Key`. == # ANALYZE is no-op for emulator. ANALYZE diff --git a/tests/conformance/data/schema_changes/foreign_key.test b/tests/conformance/data/schema_changes/foreign_key.test index 70772891..820db581 100644 --- a/tests/conformance/data/schema_changes/foreign_key.test +++ b/tests/conformance/data/schema_changes/foreign_key.test @@ -227,14 +227,16 @@ CREATE TABLE T ( ) PRIMARY KEY(A, B); == # Referenced table not found. +# --regex CREATE TABLE U ( X INT64 NOT NULL, FOREIGN KEY(X) REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: Table not found: T +ERROR:.* Table not found: T == # Duplicate schema name (CREATE TABLE). +# --regex CREATE TABLE T ( A INT64 NOT NULL ) PRIMARY KEY(A); @@ -243,9 +245,10 @@ CREATE TABLE U ( CONSTRAINT T FOREIGN KEY(X) REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: Duplicate name in schema: T. +ERROR:.* Duplicate name in schema: T. == # Duplicate schema name (ALTER TABLE). +# --regex CREATE TABLE T ( A INT64 NOT NULL ) PRIMARY KEY(A); @@ -254,7 +257,7 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE U ADD CONSTRAINT T FOREIGN KEY(X) REFERENCES T(A); -- -ERROR: Duplicate name in schema: T. +ERROR:.* Duplicate name in schema: T. == # System schema name (CREATE TABLE). # --regex @@ -266,7 +269,7 @@ CREATE TABLE U ( CONSTRAINT _T FOREIGN KEY(X) REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: [Ff]oreign [Kk]ey name not valid: _T. +ERROR:.* [Ff]oreign [Kk]ey name not valid: _T. == # System schema name (ALTER TABLE). # --regex @@ -278,7 +281,7 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE U ADD CONSTRAINT _T FOREIGN KEY(X) REFERENCES T(A); -- -ERROR: [Ff]oreign [Kk]ey name not valid: _T. +ERROR:.* [Ff]oreign [Kk]ey name not valid: _T. == # Duplicate constrained column usage. # --regex @@ -292,7 +295,7 @@ CREATE TABLE U ( FOREIGN KEY(X,X) REFERENCES T(A,B) ) PRIMARY KEY(X); -- -ERROR: Column `X` used more than once for table `U` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* Column `X` used more than once for table `U` in foreign key `FK_U_T_[A-F0-9_]+`. == # Duplicate referenced column usage. # --regex @@ -306,7 +309,7 @@ CREATE TABLE U ( FOREIGN KEY(X,Y) REFERENCES T(A,A) ) PRIMARY KEY(X); -- -ERROR: Column `A` used more than once for table `T` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* Column `A` used more than once for table `T` in foreign key `FK_U_T_[A-F0-9_]+`. == # Mismatched number of constrained and referenced columns. # --regex @@ -320,9 +323,10 @@ CREATE TABLE U ( FOREIGN KEY(X,Y) REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: The number of columns are different for table `U` and table `T` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* The number of columns are different for table `U` and table `T` in foreign key `FK_U_T_[A-F0-9_]+`. == # No constrained columns. +# --regex CREATE TABLE T ( A INT64 NOT NULL ) PRIMARY KEY(A); @@ -331,9 +335,10 @@ CREATE TABLE U ( FOREIGN KEY() REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: Error parsing Spanner DDL statement: CREATE TABLE U ( X INT64 NOT NULL, FOREIGN KEY() REFERENCES T(A) ) PRIMARY KEY(X) : Syntax error on line 4, column 15: Encountered ')' while parsing: identifier +ERROR:.* Error parsing Spanner DDL statement: CREATE TABLE U \( X INT64 NOT NULL, FOREIGN KEY\(\) REFERENCES T\(A\) \) PRIMARY KEY\(X\) : Syntax error on line 4, column 15: Encountered '\)' while parsing: identifier == # No referenced columns. +# --regex CREATE TABLE T ( A INT64 NOT NULL ) PRIMARY KEY(A); @@ -342,7 +347,7 @@ CREATE TABLE U ( FOREIGN KEY(X) REFERENCES T() ) PRIMARY KEY(X); -- -ERROR: Error parsing Spanner DDL statement: CREATE TABLE U ( X INT64 NOT NULL, FOREIGN KEY(X) REFERENCES T() ) PRIMARY KEY(X) : Syntax error on line 4, column 31: Encountered ')' while parsing: identifier +ERROR:.* Error parsing Spanner DDL statement: CREATE TABLE U \( X INT64 NOT NULL, FOREIGN KEY\(X\) REFERENCES T\(\) \) PRIMARY KEY\(X\) : Syntax error on line 4, column 31: Encountered '\)' while parsing: identifier == # Constrained column not found. # --regex @@ -354,7 +359,7 @@ CREATE TABLE U ( FOREIGN KEY(Y) REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: Column `Y` not found for table `U` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* Column `Y` not found for table `U` in foreign key `FK_U_T_[A-F0-9_]+`. == # Referenced column not found. # --regex @@ -366,7 +371,7 @@ CREATE TABLE U ( FOREIGN KEY(X) REFERENCES T(B) ) PRIMARY KEY(X); -- -ERROR: Column `B` not found for table `T` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* Column `B` not found for table `T` in foreign key `FK_U_T_[A-F0-9_]+`. == # Different column types. # --regex @@ -378,7 +383,7 @@ CREATE TABLE U ( FOREIGN KEY(X) REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: The column types are different for column `X` of table `U` and column `A` of table `T` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* The column types are different for column `X` of table `U` and column `A` of table `T` in foreign key `FK_U_T_[A-F0-9_]+`. == # Invalid constraint name. # --regex @@ -390,7 +395,7 @@ CREATE TABLE U ( CONSTRAINT PK_FK FOREIGN KEY(X) REFERENCES T(A) ) PRIMARY KEY(X); -- -ERROR: Invalid [Ff]oreign [Kk]ey name: PK_FK. Prefix PK_ cannot be used. +ERROR:.* Invalid [Ff]oreign [Kk]ey name: PK_FK. Prefix PK_ cannot be used. == # Cannot drop referenced table. # --regex @@ -407,9 +412,10 @@ CREATE TABLE V ( ) PRIMARY KEY(Y); DROP TABLE T; -- -ERROR: Cannot drop table `T`. It is referenced by one or more foreign keys: `FK_U_T_[A-F0-9_]+`, `FK_V_T_[A-F0-9_]+`. You must drop the foreign keys before dropping the table. +ERROR:.* Cannot drop table `T`. It is referenced by one or more foreign keys: `FK_U_T_[A-F0-9_]+`, `FK_V_T_[A-F0-9_]+`. You must drop the foreign keys before dropping the table. == # Cannot alter constrained column's type. +# --regex CREATE TABLE T ( A INT64 NOT NULL ) PRIMARY KEY(A); @@ -420,9 +426,10 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE U ALTER COLUMN Y FLOAT64 NOT NULL; -- -ERROR: Cannot change type of column `Y` from `INT64` to `FLOAT64` +ERROR:.* Cannot change type of column `Y` from `INT64` to `FLOAT64` == # Cannot alter referenced column's type. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B INT64 NOT NULL @@ -433,9 +440,10 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE T ALTER COLUMN B FLOAT64 NOT NULL; -- -ERROR: Cannot change type of column `B` from `INT64` to `FLOAT64` +ERROR:.* Cannot change type of column `B` from `INT64` to `FLOAT64` == # Cannot alter referenced column's nullability. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B INT64 NOT NULL, @@ -446,7 +454,7 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE T ALTER COLUMN B INT64; -- -ERROR: Cannot change the nullability for column `B` of table `T`. It is used by one or more foreign keys: `FK_U_T_FFADEDEE3430D435_1`. +ERROR:.* Cannot change the nullability for column `B` of table `T`. It is used by one or more foreign keys: `FK_U_T_FFADEDEE3430D435_1`. == # Cannot alter constrained column's nullability. # --regex @@ -460,9 +468,10 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE U ALTER COLUMN Y INT64; -- -ERROR: Cannot change the nullability for column `Y` of table `U`. It is used by one or more foreign keys: `FK_U_T_[A-F0-9_]+`. +ERROR:.* Cannot change the nullability for column `Y` of table `U`. It is used by one or more foreign keys: `FK_U_T_[A-F0-9_]+`. == # Cannot drop constrained column. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B INT64 NOT NULL, @@ -475,9 +484,10 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE U DROP COLUMN Y; -- -ERROR: Cannot drop column `Y` from table `U`. It is used by one or more foreign keys: `FK_U_T_FFADEDEE3430D435_1`, `FK_U_T_FFADEDEE3430D435_2`. You must drop the foreign keys before dropping the column. +ERROR:.* Cannot drop column `Y` from table `U`. It is used by one or more foreign keys: `FK_U_T_FFADEDEE3430D435_1`, `FK_U_T_FFADEDEE3430D435_2`. You must drop the foreign keys before dropping the column. == # Cannot drop referenced column. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B INT64 NOT NULL, @@ -492,9 +502,10 @@ CREATE TABLE V ( ) PRIMARY KEY(Y); ALTER TABLE T DROP COLUMN B; -- -ERROR: Cannot drop column `B` from table `T`. It is used by one or more foreign keys: `FK_U_T_FFADEDEE3430D435_1`, `FK_V_T_A032F46D0AA7A2F1_1`. You must drop the foreign keys before dropping the column. +ERROR:.* Cannot drop column `B` from table `T`. It is used by one or more foreign keys: `FK_U_T_FFADEDEE3430D435_1`, `FK_V_T_A032F46D0AA7A2F1_1`. You must drop the foreign keys before dropping the column. == # Invalid column type. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B ARRAY NOT NULL @@ -505,7 +516,7 @@ CREATE TABLE U ( FOREIGN KEY(Y) REFERENCES T(B) ) PRIMARY KEY(X); -- -ERROR: Column `Y` for foreign key `FK_U_T_FFADEDEE3430D435_1` on table `U` has an unsupported type. +ERROR:.* Column `Y` for foreign key `FK_U_T_FFADEDEE3430D435_1` on table `U` has an unsupported type. == # Invalid referencing commit timestamp. # --regex @@ -519,7 +530,7 @@ CREATE TABLE U ( FOREIGN KEY(Y) REFERENCES T(B) ) PRIMARY KEY(X); -- -ERROR: Commit timestamp column is not supported for column `Y` of table `U` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* Commit timestamp column is not supported for column `Y` of table `U` in foreign key `FK_U_T_[A-F0-9_]+`. == # Invalid referenced commit timestamp. # --regex @@ -533,7 +544,7 @@ CREATE TABLE U ( FOREIGN KEY(Y) REFERENCES T(B) ) PRIMARY KEY(X); -- -ERROR: Commit timestamp column is not supported for column `B` of table `T` in foreign key `FK_U_T_[A-F0-9_]+`. +ERROR:.* Commit timestamp column is not supported for column `B` of table `T` in foreign key `FK_U_T_[A-F0-9_]+`. == # Invalid set referencing commit timestamp. # --regex @@ -548,7 +559,7 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE U ALTER COLUMN Y SET OPTIONS (allow_commit_timestamp = true); -- -ERROR: Cannot set the commit_timestamp option for column `Y` of table `U`. It is used by one or more foreign keys: `FK_U_T_[A-F0-9_]+`. +ERROR:.* Cannot set the commit_timestamp option for column `Y` of table `U`. It is used by one or more foreign keys: `FK_U_T_[A-F0-9_]+`. == # Invalid set referenced commit timestamp. # --regex @@ -563,17 +574,19 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE T ALTER COLUMN B SET OPTIONS (allow_commit_timestamp = true); -- -ERROR: Cannot set the commit_timestamp option for column `B` of table `T`. It is used by one or more foreign keys: `FK_U_T_[A-F0-9_]+`. +ERROR:.* Cannot set the commit_timestamp option for column `B` of table `T`. It is used by one or more foreign keys: `FK_U_T_[A-F0-9_]+`. == # Constraint not found. +# --regex CREATE TABLE T ( A INT64 NOT NULL, ) PRIMARY KEY(A); ALTER TABLE T DROP CONSTRAINT C; -- -ERROR: C is not a constraint in T +ERROR:.* C is not a constraint in T == # Create table with duplicate constraint names. +# --regex CREATE TABLE T ( A INT64 NOT NULL, ) PRIMARY KEY(A); @@ -583,9 +596,10 @@ CREATE TABLE U ( CONSTRAINT C FOREIGN KEY(X) REFERENCES T(A), ) PRIMARY KEY(X); -- -ERROR: Duplicate name in schema: C. +ERROR:.* Duplicate name in schema: C. == # Add duplicate constraint names. +# --regex CREATE TABLE T ( A INT64 NOT NULL, ) PRIMARY KEY(A); @@ -595,9 +609,10 @@ CREATE TABLE U ( ) PRIMARY KEY(X); ALTER TABLE T ADD CONSTRAINT C FOREIGN KEY(A) REFERENCES U(X); -- -ERROR: Duplicate name in schema: C. +ERROR:.* Duplicate name in schema: C. == # Cannot drop constrained table's backing index. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B INT64 NOT NULL, @@ -609,9 +624,10 @@ CREATE TABLE U ( ) PRIMARY KEY(X); DROP INDEX IDX_U_Y_F59F82AF5FD70C80; -- -ERROR: Cannot drop index `IDX_U_Y_F59F82AF5FD70C80`. It is in use by foreign keys: `FK_U_T_FFADEDEE3430D435_1`. +ERROR:.* Cannot drop index `IDX_U_Y_F59F82AF5FD70C80`. It is in use by foreign keys: `FK_U_T_FFADEDEE3430D435_1`. == # Cannot drop referenced table's backing index. +# --regex CREATE TABLE T ( A INT64 NOT NULL, B INT64 NOT NULL, @@ -622,5 +638,5 @@ CREATE TABLE U ( ) PRIMARY KEY(X); DROP INDEX IDX_T_B_U_8EB179EFA3EE9706; -- -ERROR: Cannot drop index `IDX_T_B_U_8EB179EFA3EE9706`. It is in use by foreign keys: `FK_U_T_FFADEDEE3430D435_1`. +ERROR:.* Cannot drop index `IDX_T_B_U_8EB179EFA3EE9706`. It is in use by foreign keys: `FK_U_T_FFADEDEE3430D435_1`. == diff --git a/tests/conformance/data/schema_changes/generated_column.test b/tests/conformance/data/schema_changes/generated_column.test index 1b8383be..fbd031b8 100644 --- a/tests/conformance/data/schema_changes/generated_column.test +++ b/tests/conformance/data/schema_changes/generated_column.test @@ -100,7 +100,7 @@ CREATE TABLE T ( gen INT64 AS (ASCII(data)) STORED, ) PRIMARY KEY(id); -- -ERROR: Error parsing the definition of generated column `T`.`gen`: Unsupported built-in function: (ascii|ASCII).* +ERROR:.* Error parsing the definition of generated column `T`.`gen`: Unsupported built-in function: (ascii|ASCII).* == # NOT NULL. CREATE TABLE T ( @@ -170,9 +170,10 @@ CREATE TABLE Users ( ) PRIMARY KEY(id); ALTER TABLE Users ALTER COLUMN id_plus_one INT64 AS (id * 2) STORED; -- -ERROR: Cannot change the expression of a generated column `Users.id_plus_one` because it is stored or (has|have) other dependencies.? +ERROR:.* Cannot change the expression of a generated column `Users.id_plus_one` because it is stored or (has|have) other dependencies.? == # Cannot convert a regular column to a generated column +# --regex CREATE TABLE Users ( id INT64 NOT NULL, UserName STRING(MAX), @@ -180,9 +181,10 @@ CREATE TABLE Users ( ) PRIMARY KEY(id); ALTER TABLE Users ALTER COLUMN id_plus_one INT64 AS (id + 1) STORED; -- -ERROR: Cannot convert column `Users.id_plus_one` to a generated column. +ERROR:.* Cannot convert column `Users.id_plus_one` to a generated column. == # Cannot convert a generated column to a regular column +# --regex CREATE TABLE Users ( id INT64 NOT NULL, UserName STRING(MAX), @@ -190,9 +192,10 @@ CREATE TABLE Users ( ) PRIMARY KEY(id); ALTER TABLE Users ALTER COLUMN id_plus_one INT64; -- -ERROR: Cannot convert generated column `Users.id_plus_one` to a regular column. +ERROR:.* Cannot convert generated column `Users.id_plus_one` to a regular column. == # Cannot change the STOREDness of a generated column. +# --regex CREATE TABLE Users ( id INT64 NOT NULL, UserName STRING(MAX), @@ -200,49 +203,54 @@ CREATE TABLE Users ( ) PRIMARY KEY(id); ALTER TABLE Users ALTER COLUMN id_plus_one INT64 AS (id + 1); -- -ERROR: Generated column `id_plus_one` without the STORED attribute is not supported. +ERROR:.* Generated column `id_plus_one` without the STORED attribute is not supported. == # Generated column definition uses an unknown column. +# --regex CREATE TABLE Users ( id INT64 NOT NULL, UserName STRING(MAX), id_plus_one INT64 AS (id1 + 1) STORED, ) PRIMARY KEY(id); -- -ERROR: Error parsing the definition of generated column `Users`.`id_plus_one`: Unrecognized name: id1 [at 1:2] -(id1 + 1) - ^ +ERROR:.* Error parsing the definition of generated column `Users`.`id_plus_one`: Unrecognized name: id1 \[at 1:2] +\(id1 \+ 1\) + \^ == # Generated column definition uses an unknown column. +# --regex CREATE TABLE Users ( id INT64 NOT NULL, UserName STRING(MAX) ) PRIMARY KEY(id); ALTER TABLE Users ADD COLUMN new_column INT64 AS (unknown_column + 1) STORED; -- -ERROR: Error parsing the definition of generated column `Users`.`new_column`: Unrecognized name: unknown_column [at 1:2] -(unknown_column + 1) - ^ +ERROR:.* Error parsing the definition of generated column `Users`.`new_column`: Unrecognized name: unknown_column \[at 1:2] +\(unknown_column \+ 1\) + \^ == # Change the type of a stored generated column to a different one. +# --regex CREATE TABLE T ( id INT64 NOT NULL, expr STRING(MAX) AS (ERROR("")) STORED, ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN expr BYTES(MAX) AS (ERROR("")) STORED; -- -ERROR: Cannot change the data type of a stored generated column `T.expr`. +ERROR:.* Cannot change the data type of a stored generated column `T.expr`. == # Change the type of a stored generated column to a different one (array). +# --regex CREATE TABLE T ( id INT64 NOT NULL, expr ARRAY AS ([]) STORED, ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN expr ARRAY AS ([]) STORED; -- -ERROR: Cannot change the data type of a stored generated column `T.expr`. +ERROR:.* Cannot change the data type of a stored generated column `T.expr`. == # Change the type of a column that is used by a stored generated column. +# --regex CREATE TABLE T ( id INT64 NOT NULL, a STRING(MAX), @@ -250,9 +258,10 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN a BYTES(MAX); -- -ERROR: Cannot change the data type of column `a`, which has a dependent stored generated column. +ERROR:.* Cannot change the data type of column `a`, which has a dependent stored generated column. == # Change the subtype of an array column that is used by a stored generated column +# --regex CREATE TABLE T ( id INT64 NOT NULL, a ARRAY, @@ -260,56 +269,62 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN a ARRAY; -- -ERROR: Cannot change the data type of column `a`, which has a dependent stored generated column. +ERROR:.* Cannot change the data type of column `a`, which has a dependent stored generated column. == # Generated column definition has a type mismatch +# --regex CREATE TABLE Users ( id INT64 NOT NULL, UserName STRING(MAX), id_plus_one INT64 AS (SUBSTR(UserName, 1)) STORED, ) PRIMARY KEY(id); -- -ERROR: Error parsing the definition of generated column `Users`.`id_plus_one`: Expected type INT64; found STRING [at 1:2] -(SUBSTR(UserName, 1)) - ^ +ERROR:.* Error parsing the definition of generated column `Users`.`id_plus_one`: Expected type INT64; found STRING \[at 1:2] +\(SUBSTR\(UserName, 1\)\) + \^ == # Generated column definition has a type mismatch +# --regex CREATE TABLE GeneratedColumnDataCoalescing ( id STRING(MAX) NOT NULL, i64 INT64, gen_i64_to_b BOOL as (i64) STORED, ) PRIMARY KEY (id); -- -ERROR: Error parsing the definition of generated column `GeneratedColumnDataCoalescing`.`gen_i64_to_b`: Expected type BOOL; found INT64 [at 1:2] -(i64) - ^ +ERROR:.* Error parsing the definition of generated column `GeneratedColumnDataCoalescing`.`gen_i64_to_b`: Expected type BOOL; found INT64 \[at 1:2] +\(i64\) + \^ == # Generated column in primary key. +# --regex CREATE TABLE Users ( id INT64 NOT NULL, id_plus_one INT64 AS (id + 1) STORED ) PRIMARY KEY(id_plus_one); -- -ERROR: Generated column `Users.id_plus_one` cannot be part of the primary key. +ERROR:.* Generated column `Users.id_plus_one` cannot be part of the primary key. == # Generated column definition has a simple cycle +# --regex CREATE TABLE T ( id INT64 NOT NULL, a INT64 as (b) STORED, b INT64 as (A) STORED ) PRIMARY KEY(id); -- -ERROR: Cycle detected while analysing generated column, which include objects (a,b) +ERROR:.* Cycle detected while analysing generated column, which include objects \(a,b\) == # Generated column definition has a self reference +# --regex create table t ( id INT64 NOT NULL, a INT64 as (a+1) STORED ) PRIMARY KEY(id); -- -ERROR: Cycle detected while analysing generated column, which include objects (a) +ERROR:.* Cycle detected while analysing generated column, which include objects \(a\) == # Generated Columns: More elaborate cycle (c -> a -> b -> c) +# --regex create table t ( id INT64 NOT NULL, d INT64, @@ -318,9 +333,10 @@ create table t ( a INT64 as (b) STORED ) PRIMARY KEY(id); -- -ERROR: Cycle detected while analysing generated column, which include objects (c,a,b) +ERROR:.* Cycle detected while analysing generated column, which include objects \(c,a,b\) == # Generated Columns: Cycle a->b->c with start node being b. +# --regex create table t ( id INT64 NOT NULL, b INT64 as (c) STORED, @@ -328,11 +344,12 @@ create table t ( a INT64 as (b) STORED ) PRIMARY KEY(id); -- -ERROR: Cycle detected while analysing generated column, which include objects (b,c,a) +ERROR:.* Cycle detected while analysing generated column, which include objects \(b,c,a\) == # Interesting graph with cycles # A -> B <- C<-| # \-> D--| +# --regex create table t ( id INT64 NOT NULL, a INT64 as (b) STORED, @@ -341,36 +358,40 @@ create table t ( d INT64 as (c) STORED ) PRIMARY KEY(id); -- -ERROR: Cycle detected while analysing generated column, which include objects (a,b,d,c) +ERROR:.* Cycle detected while analysing generated column, which include objects \(a,b,d,c\) == # Cannot add a new column that introduces a cycle (self) +# --regex CREATE TABLE Users ( id INT64 NOT NULL, userName STRING(MAX) ) PRIMARY KEY(id); ALTER TABLE Users ADD COLUMN col INT64 AS (col+1) STORED; -- -ERROR: Cycle detected while analysing generated column, which include objects (col) +ERROR:.* Cycle detected while analysing generated column, which include objects \(col\) == # Generated column with an expression that is too deep. +# --regex CREATE TABLE Users ( id INT64 NOT NULL, StrCol STRING(MAX), StrExpr STRING(MAX) AS (CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, "1"))))))))))))))))))))) STORED, ) PRIMARY KEY(id); -- -ERROR: Error parsing the definition of generated column `Users`.`StrExpr`: Expression depth of 21 exceeds the maximum allowed depth of 20. +ERROR:.* Error parsing the definition of generated column `Users`.`StrExpr`: Expression depth of 21 exceeds the maximum allowed depth of 20. == # Generated column with an expression that is too deep. +# --regex CREATE TABLE Users ( id INT64 NOT NULL, StrCol STRING(MAX) ) PRIMARY KEY(id); ALTER TABLE Users ADD COLUMN StrExpr STRING(MAX) AS (CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, CONCAT(StrCol, "1"))))))))))))))))))))) STORED; -- -ERROR: Error parsing the definition of generated column `Users`.`StrExpr`: Expression depth of 21 exceeds the maximum allowed depth of 20. +ERROR:.* Error parsing the definition of generated column `Users`.`StrExpr`: Expression depth of 21 exceeds the maximum allowed depth of 20. == # Drop a column which is referenced by a generated column. +# --regex CREATE TABLE T ( id INT64, a INT64, @@ -378,9 +399,10 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T DROP COLUMN a; -- -ERROR: Cannot drop column `a` from table `T` because it is referenced by generated column `expr`. +ERROR:.* Cannot drop column `a` from table `T` because it is referenced by generated column `expr`. == # Dropping a generated column used by a generated column. +# --regex CREATE TABLE T ( id INT64, a INT64, @@ -389,9 +411,10 @@ CREATE TABLE T ( ) PRIMARY KEY (id); ALTER TABLE T DROP COLUMN expr1; -- -ERROR: Cannot drop column `expr1` from table `T` because it is referenced by generated column `expr2`. +ERROR:.* Cannot drop column `expr1` from table `T` because it is referenced by generated column `expr2`. == # Changing the type of a dependant column. +# --regex CREATE TABLE T ( id INT64, a STRING(MAX), @@ -399,58 +422,65 @@ CREATE TABLE T ( ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN a BYTES(MAX); -- -ERROR: Cannot change the data type of column `a`, which has a dependent stored generated column. +ERROR:.* Cannot change the data type of column `a`, which has a dependent stored generated column. == # Using non-scalar function in generated column. +# --regex CREATE TABLE T ( expr BOOL AS ((SELECT true) INTERSECT ALL (SELECT true)) STORED, ) PRIMARY KEY(); -- -ERROR: Error parsing the definition of generated column `T`.`expr`: Cannot use non-scalar expressions inside stored generated columns. +ERROR:.* Error parsing the definition of generated column `T`.`expr`: Cannot use non-scalar expressions inside stored generated columns. == # Subquery +# --regex CREATE TABLE TableWithSelect1 ( val INT64 AS (SELECT 1) STORED, ) PRIMARY KEY(); -- -ERROR: Error parsing the definition of generated column `TableWithSelect1`.`val`: Cannot use non-scalar expressions inside stored generated columns. +ERROR:.* Error parsing the definition of generated column `TableWithSelect1`.`val`: Cannot use non-scalar expressions inside stored generated columns. == # Nested Subquery +# --regex CREATE TABLE TableWithNestedSubquery ( val ARRAY AS (ARRAY_REVERSE(ARRAY(SELECT 1))) STORED, ) PRIMARY KEY(); -- -ERROR: Error parsing the definition of generated column `TableWithNestedSubquery`.`val`: Cannot use non-scalar expressions inside stored generated columns. +ERROR:.* Error parsing the definition of generated column `TableWithNestedSubquery`.`val`: Cannot use non-scalar expressions inside stored generated columns. == # Non-deterministic function. +# --regex CREATE TABLE T ( id INT64, expr TIMESTAMP AS (CURRENT_TIMESTAMP()) STORED, ) PRIMARY KEY(id); -- -ERROR: Error parsing the definition of generated column `T`.`expr`: Expression is non-deterministic due to the use of non-determinstic function `CURRENT_TIMESTAMP`. Expression of stored generated columns must yield the same value for the same dependent column values. Non-deterministic functions inside the expressions are not allowed. +ERROR:.* Error parsing the definition of generated column `T`.`expr`: Expression is non-deterministic due to the use of non-determinstic function `CURRENT_TIMESTAMP`. Expression of stored generated columns must yield the same value for the same dependent column values. Non-deterministic functions inside the expressions are not allowed. == # allow_commit_timestamp not allowed on dependencies of generated columns. +# --regex CREATE TABLE T( id INT64, ts TIMESTAMP OPTIONS (allow_commit_timestamp = true), expr TIMESTAMP AS (ts) STORED ) PRIMARY KEY(id); -- -ERROR: Cannot use commit timestamp column `ts` as a dependency of a materialized generated column. +ERROR:.* Cannot use commit timestamp column `ts` as a dependency of a materialized generated column. == # Adding stored generated column that uses a commit timestamp column is # disallowed. +# --regex CREATE TABLE T( id INT64, ts TIMESTAMP OPTIONS (allow_commit_timestamp = true) ) PRIMARY KEY(id); ALTER TABLE T ADD COLUMN expr TIMESTAMP AS (ts) STORED; -- -ERROR: Cannot use commit timestamp column `ts` as a dependency of a materialized generated column. +ERROR:.* Cannot use commit timestamp column `ts` as a dependency of a materialized generated column. == # Altering a column that is used by a stored generated column to be commit # timestamp is disallowed. +# --regex CREATE TABLE T( id INT64, ts TIMESTAMP, @@ -458,12 +488,13 @@ CREATE TABLE T( ) PRIMARY KEY(id); ALTER TABLE T ALTER COLUMN ts SET OPTIONS (allow_commit_timestamp = true); -- -ERROR: Cannot use commit timestamp column `ts` as a dependency of a materialized generated column. +ERROR:.* Cannot use commit timestamp column `ts` as a dependency of a materialized generated column. == # Using PENDING_COMMIT_TIMESTAMP() in generated column at CREATE TABLE. +# --regex CREATE TABLE T ( id INT64, expr TIMESTAMP AS (PENDING_COMMIT_TIMESTAMP()) STORED, ) PRIMARY KEY(id); -- -ERROR: Error parsing the definition of generated column `T`.`expr`: The PENDING_COMMIT_TIMESTAMP() function may only be used as a value for INSERT or UPDATE of an appropriately typed column. It cannot be used in SELECT, or as the input to any other scalar expression. +ERROR:.* Error parsing the definition of generated column `T`.`expr`: The PENDING_COMMIT_TIMESTAMP\(\) function may only be used as a value for INSERT or UPDATE of an appropriately typed column. It cannot be used in SELECT, or as the input to any other scalar expression. diff --git a/tests/conformance/data/schema_changes/key_column_alteration.test b/tests/conformance/data/schema_changes/key_column_alteration.test index 5ea48805..a7803f6f 100644 --- a/tests/conformance/data/schema_changes/key_column_alteration.test +++ b/tests/conformance/data/schema_changes/key_column_alteration.test @@ -1,4 +1,5 @@ # Can't alter parent key columns. +# --regex CREATE TABLE Users ( UserId STRING(20) NOT NULL ) PRIMARY KEY(UserId); @@ -7,9 +8,10 @@ CREATE TABLE Albums ( ) PRIMARY KEY(UserId), INTERLEAVE IN PARENT Users ON DELETE CASCADE; ALTER TABLE Albums ALTER COLUMN UserId STRING(40) NOT NULL; -- -ERROR: Cannot alter parent key column Albums.UserId. +ERROR:.* Cannot alter parent key column Albums.UserId. == # Remove NOT NULL from key in table with children. +# --regex CREATE TABLE Users ( UserId INT64 NOT NULL ) PRIMARY KEY(UserId); @@ -18,7 +20,7 @@ CREATE TABLE Albums ( ) PRIMARY KEY(UserId), INTERLEAVE IN PARENT Users ON DELETE CASCADE; ALTER TABLE Users ALTER COLUMN UserId INT64; -- -ERROR: Requested change to key column Users.UserId could not be made. +ERROR:.* Requested change to key column Users.UserId could not be made. == # allow_commit_timestamp option can be altered independently of # the parent key column. @@ -70,6 +72,7 @@ CREATE TABLE foo ( INTERLEAVE IN PARENT baz ON DELETE CASCADE; == # No-op alters of key columns are still invalid +# --regex CREATE TABLE T1 ( ts TIMESTAMP ) PRIMARY KEY(ts); @@ -78,4 +81,4 @@ CREATE TABLE T2 ( ) PRIMARY KEY(ts), INTERLEAVE IN PARENT T1 ON DELETE CASCADE; ALTER TABLE T2 ALTER COLUMN ts TIMESTAMP -- -ERROR: Cannot alter parent key column T2.ts. +ERROR:.* Cannot alter parent key column T2.ts. diff --git a/tests/conformance/endpoints/BUILD b/tests/conformance/endpoints/BUILD index d2ff9809..d08acaaa 100644 --- a/tests/conformance/endpoints/BUILD +++ b/tests/conformance/endpoints/BUILD @@ -24,17 +24,16 @@ cc_test( srcs = ["emulator_conformance_test.cc"], shard_count = 20, deps = [ - "@com_github_grpc_grpc//:grpc++", - "@com_google_zetasql//zetasql/base", - # disabling the heap checker as recommended by go/spanner-heapcheck - "@com_google_googletest//:gtest", - "@com_google_zetasql//zetasql/base/testing:status_matchers", - "//tests/common:proto_matchers", - "@com_github_googleapis_google_cloud_cpp//:spanner", "//common:feature_flags", "//frontend/server", + "//tests/common:proto_matchers", "//tests/common:scoped_feature_flags_setter", "//tests/conformance/cases", "//tests/conformance/common:environment", + "@com_github_googleapis_google_cloud_cpp//:spanner", + "@com_github_grpc_grpc//:grpc++", + "@com_google_googletest//:gtest", + "@com_google_zetasql//zetasql/base", + "@com_google_zetasql//zetasql/base/testing:status_matchers", ], ) diff --git a/tests/conformance/endpoints/emulator_conformance_test.cc b/tests/conformance/endpoints/emulator_conformance_test.cc index 70d2826d..1ecf7706 100644 --- a/tests/conformance/endpoints/emulator_conformance_test.cc +++ b/tests/conformance/endpoints/emulator_conformance_test.cc @@ -22,8 +22,8 @@ #include "gtest/gtest.h" #include "zetasql/base/testing/status_matchers.h" #include "tests/common/proto_matchers.h" +#include "google/cloud/spanner/admin/instance_admin_client.h" #include "google/cloud/spanner/create_instance_request_builder.h" -#include "google/cloud/spanner/instance_admin_client.h" #include "common/feature_flags.h" #include "frontend/server/server.h" #include "tests/common/scoped_feature_flags_setter.h" @@ -62,17 +62,17 @@ class EmulatorConformanceTestEnvironment : public testing::Environment { ASSERT_NE(server_, nullptr); // Initialize connection options required by the client library. - auto connection_options = - std::make_unique( - grpc::InsecureChannelCredentials()); - connection_options->set_endpoint( + auto connection_options = std::make_unique(); + connection_options->set( + grpc::InsecureChannelCredentials()); + connection_options->set( absl::StrCat(server_->host(), ":", server_->port())); // Setup an instance which will be reused for all tests. google::cloud::spanner::Instance instance(kProjectName, kInstanceName); auto instance_client = - std::make_unique( - google::cloud::spanner::MakeInstanceAdminConnection( + std::make_unique( + google::cloud::spanner_admin::MakeInstanceAdminConnection( *connection_options)); ZETASQL_ASSERT_OK(google::spanner::emulator::test::ToUtilStatusOr( instance_client