diff --git a/docs/generated/sql/bnf/delete_stmt.bnf b/docs/generated/sql/bnf/delete_stmt.bnf index 5c0266ce4c3d..4ee2789125a4 100644 --- a/docs/generated/sql/bnf/delete_stmt.bnf +++ b/docs/generated/sql/bnf/delete_stmt.bnf @@ -1,2 +1,2 @@ delete_stmt ::= - ( ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) | ) 'DELETE' 'FROM' ( ( table_name opt_index_flags ) | ( table_name opt_index_flags ) table_alias_name | ( table_name opt_index_flags ) 'AS' table_alias_name ) ( 'WHERE' a_expr | ) ( sort_clause | ) ( limit_clause | ) ( 'RETURNING' target_list | 'RETURNING' 'NOTHING' | ) + ( ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) | ) 'DELETE' 'FROM' ( ( table_name opt_index_flags ) | ( table_name opt_index_flags ) table_alias_name | ( table_name opt_index_flags ) 'AS' table_alias_name ) ( ( 'WHERE' a_expr ) | ) ( sort_clause | ) ( limit_clause | ) ( 'RETURNING' target_list | 'RETURNING' 'NOTHING' | ) diff --git a/docs/generated/sql/bnf/on_conflict.bnf b/docs/generated/sql/bnf/on_conflict.bnf index 01cf370b5e31..e7d6207f27b3 100644 --- a/docs/generated/sql/bnf/on_conflict.bnf +++ b/docs/generated/sql/bnf/on_conflict.bnf @@ -1,3 +1,3 @@ on_conflict ::= - 'ON' 'CONFLICT' ( '(' ( ( name ) ( ( ',' name ) )* ) ')' ( 'WHERE' a_expr | ) | ) 'DO' 'UPDATE' 'SET' ( ( ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) ( ( ',' ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) )* ) ( 'WHERE' a_expr | ) - | 'ON' 'CONFLICT' ( '(' ( ( name ) ( ( ',' name ) )* ) ')' ( 'WHERE' a_expr | ) | ) 'DO' 'NOTHING' + 'ON' 'CONFLICT' ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) 'DO' 'UPDATE' 'SET' ( ( ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) ( ( ',' ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) )* ) ( ( 'WHERE' a_expr ) | ) + | 'ON' 'CONFLICT' ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) 'DO' 'NOTHING' diff --git a/docs/generated/sql/bnf/simple_select_clause.bnf b/docs/generated/sql/bnf/simple_select_clause.bnf index 4fc446aee029..0bf20e72802d 100644 --- a/docs/generated/sql/bnf/simple_select_clause.bnf +++ b/docs/generated/sql/bnf/simple_select_clause.bnf @@ -1,4 +1,4 @@ simple_select_clause ::= - 'SELECT' ( 'ALL' | ) ( ( target_elem ) ( ( ',' target_elem ) )* ) ( 'FROM' ( ( table_ref ) ( ( ',' table_ref ) )* ) ( ( 'AS' 'OF' 'SYSTEM' 'TIME' a_expr ) | ) | ) ( 'WHERE' a_expr | ) ( 'GROUP' 'BY' ( ( a_expr ) ( ( ',' a_expr ) )* ) | ) ( 'HAVING' a_expr | ) ( 'WINDOW' window_definition_list | ) - | 'SELECT' ( 'DISTINCT' ) ( ( target_elem ) ( ( ',' target_elem ) )* ) ( 'FROM' ( ( table_ref ) ( ( ',' table_ref ) )* ) ( ( 'AS' 'OF' 'SYSTEM' 'TIME' a_expr ) | ) | ) ( 'WHERE' a_expr | ) ( 'GROUP' 'BY' ( ( a_expr ) ( ( ',' a_expr ) )* ) | ) ( 'HAVING' a_expr | ) ( 'WINDOW' window_definition_list | ) - | 'SELECT' ( 'DISTINCT' 'ON' '(' ( ( a_expr ) ( ( ',' a_expr ) )* ) ')' ) ( ( target_elem ) ( ( ',' target_elem ) )* ) ( 'FROM' ( ( table_ref ) ( ( ',' table_ref ) )* ) ( ( 'AS' 'OF' 'SYSTEM' 'TIME' a_expr ) | ) | ) ( 'WHERE' a_expr | ) ( 'GROUP' 'BY' ( ( a_expr ) ( ( ',' a_expr ) )* ) | ) ( 'HAVING' a_expr | ) ( 'WINDOW' window_definition_list | ) + 'SELECT' ( 'ALL' | ) ( ( target_elem ) ( ( ',' target_elem ) )* ) ( 'FROM' ( ( table_ref ) ( ( ',' table_ref ) )* ) ( ( 'AS' 'OF' 'SYSTEM' 'TIME' a_expr ) | ) | ) ( ( 'WHERE' a_expr ) | ) ( 'GROUP' 'BY' ( ( a_expr ) ( ( ',' a_expr ) )* ) | ) ( 'HAVING' a_expr | ) ( 'WINDOW' window_definition_list | ) + | 'SELECT' ( 'DISTINCT' ) ( ( target_elem ) ( ( ',' target_elem ) )* ) ( 'FROM' ( ( table_ref ) ( ( ',' table_ref ) )* ) ( ( 'AS' 'OF' 'SYSTEM' 'TIME' a_expr ) | ) | ) ( ( 'WHERE' a_expr ) | ) ( 'GROUP' 'BY' ( ( a_expr ) ( ( ',' a_expr ) )* ) | ) ( 'HAVING' a_expr | ) ( 'WINDOW' window_definition_list | ) + | 'SELECT' ( 'DISTINCT' 'ON' '(' ( ( a_expr ) ( ( ',' a_expr ) )* ) ')' ) ( ( target_elem ) ( ( ',' target_elem ) )* ) ( 'FROM' ( ( table_ref ) ( ( ',' table_ref ) )* ) ( ( 'AS' 'OF' 'SYSTEM' 'TIME' a_expr ) | ) | ) ( ( 'WHERE' a_expr ) | ) ( 'GROUP' 'BY' ( ( a_expr ) ( ( ',' a_expr ) )* ) | ) ( 'HAVING' a_expr | ) ( 'WINDOW' window_definition_list | ) diff --git a/docs/generated/sql/bnf/stmt_block.bnf b/docs/generated/sql/bnf/stmt_block.bnf index c1534c70a4e6..7cbf9a7c84c6 100644 --- a/docs/generated/sql/bnf/stmt_block.bnf +++ b/docs/generated/sql/bnf/stmt_block.bnf @@ -107,7 +107,7 @@ create_stmt ::= | create_ddl_stmt delete_stmt ::= - opt_with_clause 'DELETE' 'FROM' table_name_expr_opt_alias_idx where_clause opt_sort_clause opt_limit_clause returning_clause + opt_with_clause 'DELETE' 'FROM' table_name_expr_opt_alias_idx opt_where_clause opt_sort_clause opt_limit_clause returning_clause drop_stmt ::= drop_ddl_stmt @@ -184,7 +184,7 @@ truncate_stmt ::= 'TRUNCATE' opt_table relation_expr_list opt_drop_behavior update_stmt ::= - opt_with_clause 'UPDATE' table_name_expr_opt_alias_idx 'SET' set_clause_list where_clause opt_sort_clause opt_limit_clause returning_clause + opt_with_clause 'UPDATE' table_name_expr_opt_alias_idx 'SET' set_clause_list opt_where_clause opt_sort_clause opt_limit_clause returning_clause upsert_stmt ::= opt_with_clause 'UPSERT' 'INTO' insert_target insert_rest returning_clause @@ -326,8 +326,8 @@ table_name_expr_opt_alias_idx ::= | table_name_expr_with_index table_alias_name | table_name_expr_with_index 'AS' table_alias_name -where_clause ::= - 'WHERE' a_expr +opt_where_clause ::= + where_clause | opt_sort_clause ::= @@ -377,7 +377,7 @@ insert_rest ::= | 'DEFAULT' 'VALUES' on_conflict ::= - 'ON' 'CONFLICT' opt_conf_expr 'DO' 'UPDATE' 'SET' set_clause_list where_clause + 'ON' 'CONFLICT' opt_conf_expr 'DO' 'UPDATE' 'SET' set_clause_list opt_where_clause | 'ON' 'CONFLICT' opt_conf_expr 'DO' 'NOTHING' a_expr ::= @@ -737,7 +737,6 @@ unreserved_keyword ::= | 'TESTING_RANGES' | 'TESTING_RELOCATE' | 'TEXT' - | 'TIMESTAMPTZ' | 'TRACE' | 'TRANSACTION' | 'TRIGGER' @@ -803,6 +802,7 @@ col_name_keyword ::= | 'TIME' | 'TIMETZ' | 'TIMESTAMP' + | 'TIMESTAMPTZ' | 'TREAT' | 'TRIM' | 'VALUES' @@ -935,6 +935,9 @@ with_clause ::= table_name_expr_with_index ::= table_name opt_index_flags +where_clause ::= + 'WHERE' a_expr + sort_clause ::= 'ORDER' 'BY' sortby_list @@ -978,7 +981,7 @@ insert_column_list ::= ( insert_column_item ) ( ( ',' insert_column_item ) )* opt_conf_expr ::= - '(' name_list ')' where_clause + '(' name_list ')' | c_expr ::= @@ -1411,9 +1414,9 @@ scrub_option_list ::= ( scrub_option ) ( ( ',' scrub_option ) )* simple_select_clause ::= - 'SELECT' opt_all_clause target_list from_clause where_clause group_clause having_clause window_clause - | 'SELECT' distinct_clause target_list from_clause where_clause group_clause having_clause window_clause - | 'SELECT' distinct_on_clause target_list from_clause where_clause group_clause having_clause window_clause + 'SELECT' opt_all_clause target_list from_clause opt_where_clause group_clause having_clause window_clause + | 'SELECT' distinct_clause target_list from_clause opt_where_clause group_clause having_clause window_clause + | 'SELECT' distinct_on_clause target_list from_clause opt_where_clause group_clause having_clause window_clause values_clause ::= ( 'VALUES' '(' expr_list ')' ) ( ( ',' '(' expr_list ')' ) )* @@ -1874,12 +1877,8 @@ character_without_length ::= const_datetime ::= 'DATE' - | 'TIME' - | 'TIME' 'WITHOUT' 'TIME' 'ZONE' - | 'TIMESTAMP' - | 'TIMESTAMP' 'WITHOUT' 'TIME' 'ZONE' + | 'TIMESTAMP' opt_timezone | 'TIMESTAMPTZ' - | 'TIMESTAMP' 'WITH' 'TIME' 'ZONE' const_json ::= 'JSON' @@ -2049,6 +2048,11 @@ opt_numeric_modifiers ::= | '(' iconst64 ',' iconst64 ')' | +opt_timezone ::= + 'WITH' 'TIME' 'ZONE' + | 'WITHOUT' 'TIME' 'ZONE' + | + interval_qualifier ::= 'YEAR' | 'MONTH' diff --git a/docs/generated/sql/bnf/update_stmt.bnf b/docs/generated/sql/bnf/update_stmt.bnf index 58c10dac9131..fd5bf8e88dbe 100644 --- a/docs/generated/sql/bnf/update_stmt.bnf +++ b/docs/generated/sql/bnf/update_stmt.bnf @@ -1,2 +1,2 @@ update_stmt ::= - ( ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) | ) 'UPDATE' ( ( table_name opt_index_flags ) | ( table_name opt_index_flags ) table_alias_name | ( table_name opt_index_flags ) 'AS' table_alias_name ) 'SET' ( ( ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) ( ( ',' ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) )* ) ( 'WHERE' a_expr | ) ( sort_clause | ) ( limit_clause | ) ( 'RETURNING' target_list | 'RETURNING' 'NOTHING' | ) + ( ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) | ) 'UPDATE' ( ( table_name opt_index_flags ) | ( table_name opt_index_flags ) table_alias_name | ( table_name opt_index_flags ) 'AS' table_alias_name ) 'SET' ( ( ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) ( ( ',' ( ( column_name '=' a_expr ) | ( '(' ( ( ( column_name ) ) ( ( ',' ( column_name ) ) )* ) ')' '=' ( '(' select_stmt ')' | ( '(' ')' | '(' ( a_expr | a_expr ',' | a_expr ',' ( ( a_expr ) ( ( ',' a_expr ) )* ) ) ')' ) ) ) ) ) )* ) ( ( 'WHERE' a_expr ) | ) ( sort_clause | ) ( limit_clause | ) ( 'RETURNING' target_list | 'RETURNING' 'NOTHING' | ) diff --git a/pkg/ccl/importccl/read_import_mysql.go b/pkg/ccl/importccl/read_import_mysql.go index 4c5bb8e98b1f..b3ebd90fe901 100644 --- a/pkg/ccl/importccl/read_import_mysql.go +++ b/pkg/ccl/importccl/read_import_mysql.go @@ -612,12 +612,16 @@ func mysqlColToCockroach( def.Type = coltypes.JSON case mysqltypes.Set: - fallthrough + return nil, pgerror.UnimplementedWithIssueHintError(32560, + "cannot import SET columns at this time", + "try converting the column to a 64-bit integer before import") case mysqltypes.Geometry: - fallthrough + return nil, pgerror.UnimplementedWithIssueErrorf(32559, + "cannot import GEOMETRY columns at this time") case mysqltypes.Bit: - // TODO(dt): is our type close enough to use here? - fallthrough + return nil, pgerror.UnimplementedWithIssueHintError(32561, + "cannot improt BIT columns at this time", + "try converting the column to a 64-bit integer before import") default: return nil, pgerror.Unimplemented(fmt.Sprintf("import.mysqlcoltype.%s", typ), "unsupported mysql type %q", col.Type) } diff --git a/pkg/cmd/docgen/diagrams.go b/pkg/cmd/docgen/diagrams.go index 32e5f2d52ad8..338ef703d9ee 100644 --- a/pkg/cmd/docgen/diagrams.go +++ b/pkg/cmd/docgen/diagrams.go @@ -582,7 +582,7 @@ var specs = []stmtSpec{ }, { name: "delete_stmt", - inline: []string{"opt_with_clause", "with_clause", "cte_list", "table_name_expr_opt_alias_idx", "table_name_expr_with_index", "where_clause", "returning_clause", "opt_sort_clause", "opt_limit_clause"}, + inline: []string{"opt_with_clause", "with_clause", "cte_list", "table_name_expr_opt_alias_idx", "table_name_expr_with_index", "opt_where_clause", "where_clause", "returning_clause", "opt_sort_clause", "opt_limit_clause"}, replace: map[string]string{ "relation_expr": "table_name", }, @@ -788,7 +788,7 @@ var specs = []stmtSpec{ }, { name: "on_conflict", - inline: []string{"opt_conf_expr", "name_list", "where_clause", "set_clause_list", "insert_column_list", + inline: []string{"opt_conf_expr", "name_list", "opt_where_clause", "where_clause", "set_clause_list", "insert_column_list", "insert_column_item", "set_clause", "single_set_clause", "multiple_set_clause", "in_expr", "expr_list", "expr_tuple1_ambiguous", "tuple1_ambiguous_values"}, replace: map[string]string{ @@ -968,7 +968,7 @@ var specs = []stmtSpec{ }, { name: "simple_select_clause", - inline: []string{"opt_all_clause", "distinct_clause", "distinct_on_clause", "opt_as_of_clause", "as_of_clause", "expr_list", "target_list", "from_clause", "where_clause", "group_clause", "having_clause", "window_clause", "from_list"}, + inline: []string{"opt_all_clause", "distinct_clause", "distinct_on_clause", "opt_as_of_clause", "as_of_clause", "expr_list", "target_list", "from_clause", "opt_where_clause", "where_clause", "group_clause", "having_clause", "window_clause", "from_list"}, unlink: []string{"index_name"}, nosplit: true, }, @@ -1200,6 +1200,7 @@ var specs = []stmtSpec{ "expr_list", "expr_tuple1_ambiguous", "tuple1_ambiguous_values", + "opt_where_clause", "where_clause", "opt_sort_clause", "returning_clause", diff --git a/pkg/server/updates_test.go b/pkg/server/updates_test.go index 3ed3748b8c89..605ab9275434 100644 --- a/pkg/server/updates_test.go +++ b/pkg/server/updates_test.go @@ -527,12 +527,12 @@ func TestReportUsage(t *testing.T) { "test.b": 2, "test.c": 3, - "unimplemented.pg_catalog.pg_stat_wal_receiver": 10, - "unimplemented.syntax.alter table rename constraint": 10, - "unimplemented.syntax.interval with precision": 10, - "unimplemented.#9148": 10, - "internalerror.": 10, - "othererror.builtins.go": 10, + "unimplemented.pg_catalog.pg_stat_wal_receiver": 10, + "unimplemented.syntax.#32555": 10, + "unimplemented.syntax.#32564": 10, + "unimplemented.#9148": 10, + "internalerror.": 10, + "othererror.builtins.go": 10, "othererror." + pgerror.CodeDataExceptionError + ".crdb_internal.set_vmodule()": 10, diff --git a/pkg/sql/alter_table.go b/pkg/sql/alter_table.go index 56ab8901af40..de8acb473fee 100644 --- a/pkg/sql/alter_table.go +++ b/pkg/sql/alter_table.go @@ -97,12 +97,12 @@ func (n *alterTableNode) startExec(params runParams) error { case *tree.AlterTableAddColumn: d := t.ColumnDef if len(d.CheckExprs) > 0 { - return pgerror.Unimplemented( - "alter add check", "adding a CHECK constraint via ALTER not supported") + return pgerror.UnimplementedWithIssueError(29639, + "adding a CHECK constraint via ALTER not supported") } if d.HasFKConstraint() { - return pgerror.Unimplemented( - "alter add fk", "adding a REFERENCES constraint via ALTER not supported") + return pgerror.UnimplementedWithIssueError(8855, + "adding a REFERENCES constraint via ALTER not supported") } newDef, seqDbDesc, seqName, seqOpts, err := params.p.processSerialInColumnDef(params.ctx, d, tn) @@ -715,7 +715,9 @@ func applyColumnMutation( case schemachange.ColumnConversionTrivial: col.Type = nextType default: - return pgerror.Unimplemented("alter column type", "type conversion not yet implemented") + return pgerror.UnimplementedWithIssueDetailError(9851, + fmt.Sprintf("%s->%s", col.Type.SQLString(), nextType.SQLString()), + "type conversion not yet implemented") } case *tree.AlterTableSetDefault: diff --git a/pkg/sql/err_count_test.go b/pkg/sql/err_count_test.go index ef5a5d1fc7ae..6ce69474f988 100644 --- a/pkg/sql/err_count_test.go +++ b/pkg/sql/err_count_test.go @@ -61,3 +61,23 @@ func TestErrorCounts(t *testing.T) { t.Fatalf("expected 1 syntax error, got %d", count3-count2) } } + +func TestUnimplementedCounts(t *testing.T) { + defer leaktest.AfterTest(t)() + + params, _ := tests.CreateTestServerParams() + s, db, _ := serverutils.StartServer(t, params) + defer s.Stopper().Stop(context.TODO()) + + if _, err := db.Exec("CREATE TABLE t(x INT)"); err != nil { + t.Fatal(err) + } + + if _, err := db.Exec("ALTER TABLE t ALTER COLUMN x SET DATA TYPE STRING USING x::STRING"); err == nil { + t.Fatal("expected error, got no error") + } + + if telemetry.GetFeatureCounts()["unimplemented.#9851.INT->STRING"] == 0 { + t.Fatal("expected unimplemented telemetry, got nothing") + } +} diff --git a/pkg/sql/parser/parse_test.go b/pkg/sql/parser/parse_test.go index dc7919f9e6a0..14c6c84de388 100644 --- a/pkg/sql/parser/parse_test.go +++ b/pkg/sql/parser/parse_test.go @@ -2569,9 +2569,9 @@ func TestUnimplementedSyntax(t *testing.T) { issue int expected string }{ - {`ALTER TABLE a ALTER CONSTRAINT foo`, 0, `alter constraint`}, + {`ALTER TABLE a ALTER CONSTRAINT foo`, 31632, `alter constraint`}, {`ALTER TABLE a ALTER b SET NOT NULL`, 28751, ``}, - {`ALTER TABLE a RENAME CONSTRAINT b TO c`, 0, `alter table rename constraint`}, + {`ALTER TABLE a RENAME CONSTRAINT b TO c`, 32555, ``}, {`COMMENT ON COLUMN a.b IS 'a'`, 19472, `column`}, {`COMMENT ON DATABASE a IS 'b'`, 19472, ``}, @@ -2624,7 +2624,7 @@ func TestUnimplementedSyntax(t *testing.T) { {`DISCARD TEMPORARY`, 0, `discard temp`}, {`SET CONSTRAINTS foo`, 0, `set constraints`}, - {`SET LOCAL foo = bar`, 0, `set local`}, + {`SET LOCAL foo = bar`, 32562, ``}, {`SET foo FROM CURRENT`, 0, `set from current`}, {`CREATE TEMP TABLE a(b INT)`, 5807, ``}, @@ -2640,9 +2640,9 @@ func TestUnimplementedSyntax(t *testing.T) { {`CREATE TABLE a AS SELECT b WITH NO DATA`, 0, `create table as with no data`}, {`CREATE TABLE a(b INT AS (123) VIRTUAL)`, 0, `virtual computed columns`}, - {`CREATE TABLE a(b INT REFERENCES c(x) MATCH FULL`, 0, `references match full`}, - {`CREATE TABLE a(b INT REFERENCES c(x) MATCH PARTIAL`, 0, `references match partial`}, - {`CREATE TABLE a(b INT REFERENCES c(x) MATCH SIMPLE`, 0, `references match simple`}, + {`CREATE TABLE a(b INT REFERENCES c(x) MATCH FULL`, 20305, `match full`}, + {`CREATE TABLE a(b INT REFERENCES c(x) MATCH PARTIAL`, 20305, `match partial`}, + {`CREATE TABLE a(b INT REFERENCES c(x) MATCH SIMPLE`, 20305, `match simple`}, {`CREATE TABLE a(b INT, FOREIGN KEY (b) REFERENCES c(x) DEFERRABLE)`, 31632, `deferrable`}, {`CREATE TABLE a(b INT, FOREIGN KEY (b) REFERENCES c(x) INITIALLY DEFERRED)`, 31632, `initially deferred`}, @@ -2676,7 +2676,7 @@ func TestUnimplementedSyntax(t *testing.T) { {`CREATE INDEX a ON b(foo(c))`, 9682, ``}, {`INSERT INTO foo(a, a.b) VALUES (1,2)`, 27792, ``}, - {`INSERT INTO foo VALUES (1,2) ON CONFLICT ON CONSTRAINT a DO NOTHING`, 0, `on conflict on constraint`}, + {`INSERT INTO foo VALUES (1,2) ON CONFLICT ON CONSTRAINT a DO NOTHING`, 28161, ``}, {`SELECT * FROM ab, LATERAL (SELECT * FROM kv)`, 24560, `select`}, {`SELECT * FROM ab, LATERAL foo(a)`, 24560, `srf`}, @@ -2685,18 +2685,34 @@ func TestUnimplementedSyntax(t *testing.T) { {`SELECT * FROM a FOR UPDATE`, 6583, ``}, {`SELECT * FROM ROWS FROM (a(b) AS (d))`, 0, `ROWS FROM with col_def_list`}, + {`SELECT 123 AT TIME ZONE 'b'`, 32005, ``}, + {`SELECT 'a'::INTERVAL SECOND`, 0, `interval with unit qualifier`}, - {`SELECT 'a'::INTERVAL(123)`, 0, `interval with precision`}, - {`SELECT 'a'::INTERVAL SECOND(123)`, 0, `interval second with precision`}, - {`SELECT 123 AT TIME ZONE 'b'`, 0, `at tz`}, + {`SELECT 'a'::INTERVAL(123)`, 32564, ``}, + {`SELECT 'a'::INTERVAL SECOND(123)`, 32564, `interval second`}, + {`SELECT INTERVAL(3) 'a'`, 32564, ``}, + + {`SELECT 'a'::TIMESTAMP(123)`, 32098, ``}, + {`SELECT 'a'::TIMESTAMP(123) WITHOUT TIME ZONE`, 32098, ``}, + {`SELECT 'a'::TIMESTAMPTZ(123)`, 32098, ``}, + {`SELECT 'a'::TIMESTAMP(123) WITH TIME ZONE`, 32098, ``}, + {`SELECT TIMESTAMP(3) 'a'`, 32098, ``}, + {`SELECT TIMESTAMPTZ(3) 'a'`, 32098, ``}, + + {`SELECT 'a'::TIME(123)`, 32565, ``}, + {`SELECT 'a'::TIME(123) WITHOUT TIME ZONE`, 32565, ``}, + {`SELECT 'a'::TIMETZ(123)`, 26097, `type with precision`}, + {`SELECT 'a'::TIME(123) WITH TIME ZONE`, 32565, ``}, + {`SELECT TIME(3) 'a'`, 32565, ``}, + {`SELECT TIMETZ(3) 'a'`, 26097, `type with precision`}, + + {`SELECT a(b) 'c'`, 0, `a(...) SCONST`}, {`SELECT (a,b) OVERLAPS (c,d)`, 0, `overlaps`}, {`SELECT UNIQUE (SELECT b)`, 0, `UNIQUE predicate`}, - {`SELECT a(b) 'c'`, 0, `func const`}, - {`SELECT INTERVAL(3) 'a'`, 0, `expr_const const_interval`}, {`SELECT GROUPING (a,b,c)`, 0, `d_expr grouping`}, {`SELECT a(VARIADIC b)`, 0, `variadic`}, {`SELECT a(b, c, VARIADIC b)`, 0, `variadic`}, - {`SELECT COLLATION FOR (a)`, 0, `func_expr_common_subexpr collation for`}, + {`SELECT COLLATION FOR (a)`, 32563, ``}, {`SELECT CURRENT_TIME`, 26097, `current_time`}, {`SELECT CURRENT_TIME()`, 26097, `current_time`}, {`SELECT TREAT (a AS INT)`, 0, `treat`}, @@ -2720,6 +2736,8 @@ func TestUnimplementedSyntax(t *testing.T) { {`CREATE TABLE a(b XML)`, 0, `xml`}, {`CREATE TABLE a(b TIMETZ)`, 26097, `type`}, + {`INSERT INTO a VALUES (1) ON CONFLICT (x) WHERE x > 3 DO NOTHING`, 32557, ``}, + {`WITH RECURSIVE a AS (TABLE b) SELECT c`, 21085, ``}, {`UPDATE foo SET (a, a.b) = (1, 2)`, 27792, ``}, diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index a7e7e6714f30..79794121e597 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -851,7 +851,7 @@ func newNameFromStr(s string) *tree.Name { %type opt_storing %type <*tree.ColumnTableDef> column_def %type table_elem -%type where_clause +%type where_clause opt_where_clause %type <*tree.ArraySubscript> array_subscript %type opt_slice_bound %type <*tree.IndexFlags> opt_index_flags @@ -890,6 +890,7 @@ func newNameFromStr(s string) *tree.Name { %type <[]string> explain_option_list %type typename simple_typename const_typename +%type opt_timezone %type numeric opt_numeric_modifiers %type opt_float %type character_with_length character_without_length @@ -1537,7 +1538,7 @@ alter_table_cmd: } } // ALTER TABLE ALTER CONSTRAINT ... -| ALTER CONSTRAINT constraint_name error { return unimplemented(sqllex, "alter constraint") } +| ALTER CONSTRAINT constraint_name error { return unimplementedWithIssueDetail(sqllex, 31632, "alter constraint") } // ALTER TABLE VALIDATE CONSTRAINT ... | VALIDATE CONSTRAINT constraint_name { @@ -2178,7 +2179,7 @@ opt_changefeed_sink: // [RETURNING ] // %SeeAlso: WEBDOCS/delete.html delete_stmt: - opt_with_clause DELETE FROM table_name_expr_opt_alias_idx where_clause opt_sort_clause opt_limit_clause returning_clause + opt_with_clause DELETE FROM table_name_expr_opt_alias_idx opt_where_clause opt_sort_clause opt_limit_clause returning_clause { $$.val = &tree.Delete{ With: $1.with(), @@ -2658,7 +2659,7 @@ nonpreparable_set_stmt: set_transaction_stmt // EXTEND WITH HELP: SET TRANSACTION | set_exprs_internal { /* SKIP DOC */ } | SET CONSTRAINTS error { return unimplemented(sqllex, "set constraints") } -| SET LOCAL error { return unimplemented(sqllex, "set local") } +| SET LOCAL error { return unimplementedWithIssue(sqllex, 32562) } // SET SESSION / SET CLUSTER SETTING preparable_set_stmt: @@ -4343,10 +4344,27 @@ opt_column_list: $$.val = tree.NameList(nil) } +// https://www.postgresql.org/docs/10/sql-createtable.html +// +// "A value inserted into the referencing column(s) is matched against +// the values of the referenced table and referenced columns using the +// given match type. There are three match types: MATCH FULL, MATCH +// PARTIAL, and MATCH SIMPLE (which is the default). MATCH FULL will +// not allow one column of a multicolumn foreign key to be null unless +// all foreign key columns are null; if they are all null, the row is +// not required to have a match in the referenced table. MATCH SIMPLE +// allows any of the foreign key columns to be null; if any of them +// are null, the row is not required to have a match in the referenced +// table. MATCH PARTIAL is not yet implemented. (Of course, NOT NULL +// constraints can be applied to the referencing column(s) to prevent +// these cases from arising.)" +// +// Note: CockroachDB's silent default is closer in semantics to pg's +// MATCH FULL. This is arguably a bug. See discussion in #20305. key_match: - MATCH FULL { return unimplemented(sqllex, "references match full") } -| MATCH PARTIAL { return unimplemented(sqllex, "references match partial") } -| MATCH SIMPLE { return unimplemented(sqllex, "references match simple") } + MATCH FULL { return unimplementedWithIssueDetail(sqllex, 20305, "match full") } +| MATCH PARTIAL { return unimplementedWithIssueDetail(sqllex, 20305, "match partial") } +| MATCH SIMPLE { return unimplementedWithIssueDetail(sqllex, 20305, "match simple") } | /* EMPTY */ {} // We combine the update and delete actions into one value temporarily for @@ -4833,9 +4851,9 @@ alter_rename_table_stmt: } } | ALTER TABLE relation_expr RENAME CONSTRAINT constraint_name TO constraint_name - { return unimplemented(sqllex, "alter table rename constraint") } + { return unimplementedWithIssue(sqllex, 32555) } | ALTER TABLE IF EXISTS relation_expr RENAME CONSTRAINT constraint_name TO constraint_name - { return unimplemented(sqllex, "alter table rename constraint") } + { return unimplementedWithIssue(sqllex, 32555) } alter_rename_view_stmt: ALTER VIEW relation_expr RENAME TO view_name @@ -5318,7 +5336,7 @@ insert_column_item: | column_name '.' error { return unimplementedWithIssue(sqllex, 27792) } on_conflict: - ON CONFLICT opt_conf_expr DO UPDATE SET set_clause_list where_clause + ON CONFLICT opt_conf_expr DO UPDATE SET set_clause_list opt_where_clause { $$.val = &tree.OnConflict{Columns: $3.nameList(), Exprs: $7.updateExprs(), Where: tree.NewWhere(tree.AstWhere, $8.expr())} } @@ -5328,12 +5346,12 @@ on_conflict: } opt_conf_expr: - '(' name_list ')' where_clause + '(' name_list ')' { - // TODO(dan): Support the where_clause. $$.val = $2.nameList() } -| ON CONSTRAINT constraint_name { return unimplemented(sqllex, "on conflict on constraint") } +| '(' name_list ')' where_clause { return unimplementedWithIssue(sqllex, 32557) } +| ON CONSTRAINT constraint_name { return unimplementedWithIssue(sqllex, 28161) } | /* EMPTY */ { $$.val = tree.NameList(nil) @@ -5366,7 +5384,7 @@ returning_clause: // %SeeAlso: INSERT, UPSERT, DELETE, WEBDOCS/update.html update_stmt: opt_with_clause UPDATE table_name_expr_opt_alias_idx - SET set_clause_list update_from_clause where_clause opt_sort_clause opt_limit_clause returning_clause + SET set_clause_list update_from_clause opt_where_clause opt_sort_clause opt_limit_clause returning_clause { $$.val = &tree.Update{ With: $1.with(), @@ -5567,7 +5585,7 @@ simple_select: // %SeeAlso: WEBDOCS/select-clause.html simple_select_clause: SELECT opt_all_clause target_list - from_clause where_clause + from_clause opt_where_clause group_clause having_clause window_clause { $$.val = &tree.SelectClause{ @@ -5580,7 +5598,7 @@ simple_select_clause: } } | SELECT distinct_clause target_list - from_clause where_clause + from_clause opt_where_clause group_clause having_clause window_clause { $$.val = &tree.SelectClause{ @@ -5594,7 +5612,7 @@ simple_select_clause: } } | SELECT distinct_on_clause target_list - from_clause where_clause + from_clause opt_where_clause group_clause having_clause window_clause { $$.val = &tree.SelectClause{ @@ -6348,6 +6366,9 @@ where_clause: { $$.val = $2.expr() } + +opt_where_clause: + where_clause | /* EMPTY */ { $$.val = tree.Expr(nil) @@ -6429,7 +6450,7 @@ simple_typename: | character_with_length | const_interval | const_interval interval_qualifier { return unimplemented(sqllex, "interval with unit qualifier") } -| const_interval '(' ICONST ')' { return unimplemented(sqllex, "interval with precision") } +| const_interval '(' ICONST ')' { return unimplementedWithIssue(sqllex, 32564) } // We have a separate const_typename to allow defaulting fixed-length types // such as CHAR() and BIT() to an unspecified length. SQL9x requires that these @@ -6764,38 +6785,34 @@ const_datetime: { $$.val = coltypes.Date } -| TIME +| TIME opt_timezone { + if $2.bool() { return unimplementedWithIssueDetail(sqllex, 26097, "type") } $$.val = coltypes.Time } -| TIME WITHOUT TIME ZONE +| TIME '(' ICONST ')' opt_timezone { return unimplementedWithIssue(sqllex, 32565) } +| TIMETZ { return unimplementedWithIssueDetail(sqllex, 26097, "type") } +| TIMETZ '(' ICONST ')' { return unimplementedWithIssueDetail(sqllex, 26097, "type with precision") } +| TIMESTAMP opt_timezone { - $$.val = coltypes.Time - } -| TIMETZ - { - return unimplementedWithIssueDetail(sqllex, 26097, "type") - } -| TIME WITH_LA TIME ZONE - { - return unimplementedWithIssueDetail(sqllex, 26097, "type") - } -| TIMESTAMP - { - $$.val = coltypes.Timestamp - } -| TIMESTAMP WITHOUT TIME ZONE - { - $$.val = coltypes.Timestamp + if $2.bool() { + $$.val = coltypes.TimestampWithTZ + } else { + $$.val = coltypes.Timestamp + } } +| TIMESTAMP '(' ICONST ')' opt_timezone { return unimplementedWithIssue(sqllex, 32098) } | TIMESTAMPTZ { $$.val = coltypes.TimestampWithTZ } -| TIMESTAMP WITH_LA TIME ZONE - { - $$.val = coltypes.TimestampWithTZ - } +| TIMESTAMPTZ '(' ICONST ')' { return unimplementedWithIssue(sqllex, 32098) } + +opt_timezone: + WITH_LA TIME ZONE { $$.val = true; } +| WITHOUT TIME ZONE { $$.val = false; } +| /*EMPTY*/ { $$.val = false; } + const_interval: INTERVAL { @@ -6870,7 +6887,7 @@ interval_second: { $$.val = tree.Second } -| SECOND '(' ICONST ')' { return unimplemented(sqllex, "interval second with precision") } +| SECOND '(' ICONST ')' { return unimplementedWithIssueDetail(sqllex, 32564, "interval second") } // General expressions. This is the heart of the expression syntax. // @@ -6905,7 +6922,7 @@ a_expr: { $$.val = &tree.CollateExpr{Expr: $1.expr(), Locale: $3} } -| a_expr AT TIME ZONE a_expr %prec AT { return unimplemented(sqllex, "at tz") } +| a_expr AT TIME ZONE a_expr %prec AT { return unimplementedWithIssue(sqllex, 32005) } // These operators must be called out explicitly in order to make use of // bison's automatic operator-precedence handling. All other operator names // are handled by the generic productions using "OP", below; and all those @@ -7445,7 +7462,7 @@ d_expr: if err != nil { sqllex.Error(err.Error()); return 1 } $$.val = d } -| func_name '(' expr_list opt_sort_clause_err ')' SCONST { return unimplemented(sqllex, "func const") } +| func_name '(' expr_list opt_sort_clause_err ')' SCONST { return unimplemented(sqllex, $1.unresolvedName().String() + "(...) SCONST") } | const_typename SCONST { $$.val = &tree.CastExpr{Expr: tree.NewStrVal($2), Type: $1.colType(), SyntaxMode: tree.CastPrepend} @@ -7454,7 +7471,7 @@ d_expr: { $$.val = $1.expr() } -| const_interval '(' ICONST ')' SCONST { return unimplemented(sqllex, "expr_const const_interval") } +| const_interval '(' ICONST ')' SCONST { return unimplementedWithIssue(sqllex, 32564) } | TRUE { $$.val = tree.MakeDBool(true) @@ -7575,7 +7592,7 @@ func_expr_windowless: // Special expressions that are considered to be functions. func_expr_common_subexpr: - COLLATION FOR '(' a_expr ')' { return unimplemented(sqllex, "func_expr_common_subexpr collation for") } + COLLATION FOR '(' a_expr ')' { return unimplementedWithIssue(sqllex, 32563) } | CURRENT_DATE { $$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)} @@ -8949,7 +8966,6 @@ unreserved_keyword: | TESTING_RANGES | TESTING_RELOCATE | TEXT -| TIMESTAMPTZ | TRACE | TRANSACTION | TRIGGER @@ -9024,6 +9040,7 @@ col_name_keyword: | TIME | TIMETZ | TIMESTAMP +| TIMESTAMPTZ | TREAT | TRIM | VALUES diff --git a/pkg/sql/sequence.go b/pkg/sql/sequence.go index eb3a067c404d..a79c2f4c6336 100644 --- a/pkg/sql/sequence.go +++ b/pkg/sql/sequence.go @@ -229,7 +229,7 @@ func assignSequenceOptions( switch option.Name { case tree.SeqOptCycle: - return pgerror.NewError(pgerror.CodeFeatureNotSupportedError, + return pgerror.UnimplementedWithIssueError(20961, "CYCLE option is not supported") case tree.SeqOptNoCycle: // Do nothing; this is the default. @@ -242,7 +242,7 @@ func assignSequenceOptions( case v == 1: // Do nothing; this is the default. case v > 1: - return pgerror.NewErrorf(pgerror.CodeFeatureNotSupportedError, + return pgerror.UnimplementedWithIssueErrorf(32567, "CACHE values larger than 1 are not supported, found %d", v) } case tree.SeqOptIncrement: