From 7e3ad70f54c69d7ce3c18c7672a4a70d99e6cf9d Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Wed, 9 Dec 2020 13:15:33 +0530 Subject: [PATCH 1/3] Added rails tests Signed-off-by: GuptaManan100 --- .../planbuilder/testdata/from_cases.txt | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt index b85e65681f4..9130171ab51 100644 --- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt @@ -2258,3 +2258,129 @@ ] } } + +#rails_query 2 +"SELECT * FROM information_schema.schemata WHERE schema_name = 'user'" +{ +} + +#rails_query 3 +"SELECT table_comment FROM information_schema.tables WHERE table_schema = 'schema_name' AND table_name = 'table_name'" +{ + "QueryType": "SELECT", + "Original": "SELECT table_comment FROM information_schema.tables WHERE table_schema = 'schema_name' AND table_name = 'table_name'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select table_comment from information_schema.`tables` where 1 != 1", + "Query": "select table_comment from information_schema.`tables` where table_schema = :__vtschemaname and table_name = :__vttablename", + "SysTableTableName": "VARBINARY(\"table_name\")", + "SysTableTableSchema": "VARBINARY(\"schema_name\")" + } +} + +#rails_query 4 +"SELECT fk.referenced_table_name AS 'to_table', fk.referenced_column_name AS 'primary_key',fk.column_name AS 'column',fk.constraint_name AS 'name',rc.update_rule AS 'on_update',rc.delete_rule AS 'on_delete' FROM information_schema.referential_constraints rc JOIN information_schema.key_column_usage fk USING (constraint_schema, constraint_name) WHERE fk.referenced_column_name IS NOT NULL AND fk.table_schema = 'table_schema' AND fk.table_name = 'table_name' AND rc.constraint_schema = 'table_schema' AND rc.table_name = 'table_name'" +{ +} + +#rails_query 5 +"SELECT cc.constraint_name AS 'name', cc.check_clause AS 'expression' FROM information_schema.check_constraints cc JOIN information_schema.table_constraints tc USING (constraint_schema, constraint_name) WHERE tc.table_schema = 'table_schema' AND tc.table_name = 'table_name' AND cc.constraint_schema = 'constraint_schema'" +{ +} + +#rails_query 6 +"SELECT column_name FROM information_schema.statistics WHERE index_name = 'PRIMARY' AND table_schema = 'table_schema' AND table_name = 'table_name' ORDER BY seq_in_index" +{ + "QueryType": "SELECT", + "Original": "SELECT column_name FROM information_schema.statistics WHERE index_name = 'PRIMARY' AND table_schema = 'table_schema' AND table_name = 'table_name' ORDER BY seq_in_index", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select column_name from information_schema.statistics where 1 != 1", + "Query": "select column_name from information_schema.statistics where index_name = 'PRIMARY' and table_schema = :__vtschemaname and table_name = :__vttablename order by seq_in_index asc", + "SysTableTableName": "VARBINARY(\"table_name\")", + "SysTableTableSchema": "VARBINARY(\"table_schema\")" + } +} + +#rails_query 7 +"SELECT generation_expression FROM information_schema.columns WHERE table_schema = 'table_schema' AND table_name = 'table_name' AND column_name = 'column_name'" +{ + "QueryType": "SELECT", + "Original": "SELECT generation_expression FROM information_schema.columns WHERE table_schema = 'table_schema' AND table_name = 'table_name' AND column_name = 'column_name'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select generation_expression from information_schema.`columns` where 1 != 1", + "Query": "select generation_expression from information_schema.`columns` where table_schema = :__vtschemaname and table_name = :__vttablename and column_name = 'column_name'", + "SysTableTableName": "VARBINARY(\"table_name\")", + "SysTableTableSchema": "VARBINARY(\"table_schema\")" + } +} + +#rails_query 8 +"SELECT id FROM information_schema.processlist WHERE info LIKE '% FOR UPDATE'" +{ + "QueryType": "SELECT", + "Original": "SELECT id FROM information_schema.processlist WHERE info LIKE '% FOR UPDATE'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select id from information_schema.`processlist` where 1 != 1", + "Query": "select id from information_schema.`processlist` where info like '% FOR UPDATE'" + } +} + +#rails_query 9 +"SELECT table_name FROM (SELECT * FROM information_schema.tables WHERE table_schema = 'table_schema') _subquery" +{ + "QueryType": "SELECT", + "Original": "SELECT table_name FROM (SELECT * FROM information_schema.tables WHERE table_schema = 'table_schema') _subquery", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1", + "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery", + "SysTableTableSchema": "VARBINARY(\"table_schema\")" + } +} + +#rails_query 10 +"SELECT table_name FROM (SELECT * FROM information_schema.tables WHERE table_schema = 'table_schema') _subquery WHERE _subquery.table_type = 'table_type' AND _subquery.table_name = 'table_name'" +{ + "QueryType": "SELECT", + "Original": "SELECT table_name FROM (SELECT * FROM information_schema.tables WHERE table_schema = 'table_schema') _subquery WHERE _subquery.table_type = 'table_type' AND _subquery.table_name = 'table_name'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1", + "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery where _subquery.table_type = 'table_type' and _subquery.table_name = :__vttablename", + "SysTableTableName": "VARBINARY(\"table_name\")", + "SysTableTableSchema": "VARBINARY(\"table_schema\")" + } +} From 18417d65a896cd29efd0c5fcf877f5262c213882 Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Wed, 9 Dec 2020 14:28:42 +0530 Subject: [PATCH 2/3] added support for constraint_schema and schema_name columns Signed-off-by: GuptaManan100 --- go/vt/vtgate/executor_select_test.go | 2 +- go/vt/vtgate/planbuilder/system_tables.go | 4 +- .../planbuilder/testdata/filter_cases.txt | 2 +- .../planbuilder/testdata/from_cases.txt | 80 +++++++++++++++++++ .../testdata/unsupported_cases.txt | 4 + 5 files changed, 88 insertions(+), 4 deletions(-) diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index aee0e89f424..5a5745c99b1 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -2417,7 +2417,7 @@ func TestSelectFromInformationSchema(t *testing.T) { // check failure when trying to query two keyspaces _, err := exec(executor, session, "SELECT B.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES AS A, INFORMATION_SCHEMA.COLUMNS AS B WHERE A.TABLE_SCHEMA = 'TestExecutor' AND A.TABLE_SCHEMA = 'TestXBadSharding'") require.Error(t, err) - require.Contains(t, err.Error(), "two predicates for table_schema not supported") + require.Contains(t, err.Error(), "two predicates for specifying the database are not supported") // we pick a keyspace and query for table_schema = database(). should be routed to the picked keyspace session.TargetString = "TestExecutor" diff --git a/go/vt/vtgate/planbuilder/system_tables.go b/go/vt/vtgate/planbuilder/system_tables.go index 00285e4ab61..43e7d7b0878 100644 --- a/go/vt/vtgate/planbuilder/system_tables.go +++ b/go/vt/vtgate/planbuilder/system_tables.go @@ -37,7 +37,7 @@ func (pb *primitiveBuilder) findSysInfoRoutingPredicates(expr sqlparser.Expr, ru if isTableSchema { if rut.eroute.SysTableTableSchema != nil { - return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "two predicates for table_schema not supported") + return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "two predicates for specifying the database are not supported") } rut.eroute.SysTableTableSchema = out } else { @@ -70,7 +70,7 @@ func isTableSchemaOrName(e sqlparser.Expr) (isTableSchema bool, isTableName bool if !ok { return false, false } - return col.Name.EqualString("table_schema"), col.Name.EqualString("table_name") + return col.Name.EqualString("table_schema") || col.Name.EqualString("constraint_schema") || col.Name.EqualString("schema_name"), col.Name.EqualString("table_name") } func extractInfoSchemaRoutingPredicate(in sqlparser.Expr) (bool, evalengine.Expr, error) { diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt index 01f8cf364bc..48682ad7d6d 100644 --- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt @@ -1683,7 +1683,7 @@ # query trying to query two different keyspaces at the same time "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'user' AND TABLE_SCHEMA = 'main'" -"two predicates for table_schema not supported" +"two predicates for specifying the database are not supported" # information_schema query using database() func "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = database()" diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt index 9130171ab51..de556feefa7 100644 --- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt @@ -2262,6 +2262,19 @@ #rails_query 2 "SELECT * FROM information_schema.schemata WHERE schema_name = 'user'" { + "QueryType": "SELECT", + "Original": "SELECT * FROM information_schema.schemata WHERE schema_name = 'user'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select * from information_schema.schemata where 1 != 1", + "Query": "select * from information_schema.schemata where schema_name = :__vtschemaname", + "SysTableTableSchema": "VARBINARY(\"user\")" + } } #rails_query 3 @@ -2286,11 +2299,78 @@ #rails_query 4 "SELECT fk.referenced_table_name AS 'to_table', fk.referenced_column_name AS 'primary_key',fk.column_name AS 'column',fk.constraint_name AS 'name',rc.update_rule AS 'on_update',rc.delete_rule AS 'on_delete' FROM information_schema.referential_constraints rc JOIN information_schema.key_column_usage fk USING (constraint_schema, constraint_name) WHERE fk.referenced_column_name IS NOT NULL AND fk.table_schema = 'table_schema' AND fk.table_name = 'table_name' AND rc.constraint_schema = 'table_schema' AND rc.table_name = 'table_name'" { + "QueryType": "SELECT", + "Original": "SELECT fk.referenced_table_name AS 'to_table', fk.referenced_column_name AS 'primary_key',fk.column_name AS 'column',fk.constraint_name AS 'name',rc.update_rule AS 'on_update',rc.delete_rule AS 'on_delete' FROM information_schema.referential_constraints rc JOIN information_schema.key_column_usage fk USING (constraint_schema, constraint_name) WHERE fk.referenced_column_name IS NOT NULL AND fk.table_schema = 'table_schema' AND fk.table_name = 'table_name' AND rc.constraint_schema = 'table_schema' AND rc.table_name = 'table_name'", + "Instructions": { + "OperatorType": "Join", + "Variant": "Join", + "JoinColumnIndexes": "1,2,3,4,-1,-2", + "TableName": "_", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select rc.update_rule as on_update, rc.delete_rule as on_delete, rc.constraint_schema, rc.constraint_name from information_schema.referential_constraints as rc where 1 != 1", + "Query": "select rc.update_rule as on_update, rc.delete_rule as on_delete, rc.constraint_schema, rc.constraint_name from information_schema.referential_constraints as rc where rc.constraint_schema = :__vtschemaname and rc.table_name = :__vttablename", + "SysTableTableName": "VARBINARY(\"table_name\")", + "SysTableTableSchema": "VARBINARY(\"table_schema\")" + }, + { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name` from information_schema.key_column_usage as fk where 1 != 1", + "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name` from information_schema.key_column_usage as fk where fk.constraint_schema = :rc_constraint_schema and fk.constraint_name = :rc_constraint_name and fk.referenced_column_name is not null and fk.table_schema = :__vtschemaname and fk.table_name = :__vttablename", + "SysTableTableName": "VARBINARY(\"table_name\")", + "SysTableTableSchema": "VARBINARY(\"table_schema\")" + } + ] + } } #rails_query 5 "SELECT cc.constraint_name AS 'name', cc.check_clause AS 'expression' FROM information_schema.check_constraints cc JOIN information_schema.table_constraints tc USING (constraint_schema, constraint_name) WHERE tc.table_schema = 'table_schema' AND tc.table_name = 'table_name' AND cc.constraint_schema = 'constraint_schema'" { + "QueryType": "SELECT", + "Original": "SELECT cc.constraint_name AS 'name', cc.check_clause AS 'expression' FROM information_schema.check_constraints cc JOIN information_schema.table_constraints tc USING (constraint_schema, constraint_name) WHERE tc.table_schema = 'table_schema' AND tc.table_name = 'table_name' AND cc.constraint_schema = 'constraint_schema'", + "Instructions": { + "OperatorType": "Join", + "Variant": "Join", + "JoinColumnIndexes": "-1,-2", + "TableName": "_", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select cc.constraint_name as `name`, cc.check_clause as expression, cc.constraint_schema from information_schema.check_constraints as cc where 1 != 1", + "Query": "select cc.constraint_name as `name`, cc.check_clause as expression, cc.constraint_schema from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname", + "SysTableTableSchema": "VARBINARY(\"constraint_schema\")" + }, + { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select 1 from information_schema.table_constraints as tc where 1 != 1", + "Query": "select 1 from information_schema.table_constraints as tc where tc.constraint_schema = :cc_constraint_schema and tc.constraint_name = :cc_constraint_name and tc.table_schema = :__vtschemaname and tc.table_name = :__vttablename", + "SysTableTableName": "VARBINARY(\"table_name\")", + "SysTableTableSchema": "VARBINARY(\"table_schema\")" + } + ] + } } #rails_query 6 diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt index 31593d3c99d..e25e3cf923d 100644 --- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt @@ -377,3 +377,7 @@ # Multi shard query using into outfile s3 "select * from user into outfile s3 'out_file_name'" "unsupported: this construct is not supported on sharded keyspace" + +# unsupported two predicates specifying the database for the same table +"SELECT cc.constraint_name AS 'name' FROM information_schema.check_constraints cc WHERE cc.constraint_schema = 'constraint_schema' AND cc.table_schema = 'a'" +"two predicates for specifying the database are not supported" From 7994d9a7faceaed97aa9c9719f1fdd1206dd907c Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Wed, 9 Dec 2020 16:51:25 +0530 Subject: [PATCH 3/3] allow two predicates if they refer to the same table or schema Signed-off-by: GuptaManan100 --- go/vt/vtgate/evalengine/expressions.go | 12 ++++++++++++ go/vt/vtgate/planbuilder/system_tables.go | 4 ++-- .../planbuilder/testdata/from_cases.txt | 19 +++++++++++++++++++ .../testdata/unsupported_cases.txt | 2 +- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/go/vt/vtgate/evalengine/expressions.go b/go/vt/vtgate/evalengine/expressions.go index a32badee480..baafbe8a0c2 100644 --- a/go/vt/vtgate/evalengine/expressions.go +++ b/go/vt/vtgate/evalengine/expressions.go @@ -327,3 +327,15 @@ func evaluateByType(val *querypb.BindVariable) (EvalResult, error) { func (e *EvalResult) debugString() string { return fmt.Sprintf("(%s) %d %d %f %s", querypb.Type_name[int32(e.typ)], e.ival, e.uval, e.fval, string(e.bytes)) } + +// AreExprEqual checks if the provided Expr are the same or not +func AreExprEqual(expr1 Expr, expr2 Expr) bool { + // Check the types of the two expressions, if they don't match then the two are not equal + if fmt.Sprintf("%T", expr1) != fmt.Sprintf("%T", expr2) { + return false + } + if expr1.String() == expr2.String() { + return true + } + return false +} diff --git a/go/vt/vtgate/planbuilder/system_tables.go b/go/vt/vtgate/planbuilder/system_tables.go index 43e7d7b0878..3bf7f8ea7d3 100644 --- a/go/vt/vtgate/planbuilder/system_tables.go +++ b/go/vt/vtgate/planbuilder/system_tables.go @@ -36,12 +36,12 @@ func (pb *primitiveBuilder) findSysInfoRoutingPredicates(expr sqlparser.Expr, ru } if isTableSchema { - if rut.eroute.SysTableTableSchema != nil { + if rut.eroute.SysTableTableSchema != nil && !evalengine.AreExprEqual(rut.eroute.SysTableTableSchema, out) { return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "two predicates for specifying the database are not supported") } rut.eroute.SysTableTableSchema = out } else { - if rut.eroute.SysTableTableName != nil { + if rut.eroute.SysTableTableName != nil && !evalengine.AreExprEqual(rut.eroute.SysTableTableName, out) { return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "two predicates for table_name not supported") } rut.eroute.SysTableTableName = out diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt index de556feefa7..44358a1a304 100644 --- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt @@ -2464,3 +2464,22 @@ "SysTableTableSchema": "VARBINARY(\"table_schema\")" } } + +# two predicates specifying the database for the same table work if the database is the same +"SELECT cc.constraint_name AS 'name' FROM information_schema.check_constraints cc WHERE cc.constraint_schema = 'a' AND cc.table_schema = 'a'" +{ + "QueryType": "SELECT", + "Original": "SELECT cc.constraint_name AS 'name' FROM information_schema.check_constraints cc WHERE cc.constraint_schema = 'a' AND cc.table_schema = 'a'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where 1 != 1", + "Query": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname and cc.table_schema = :__vtschemaname", + "SysTableTableSchema": "VARBINARY(\"a\")" + } +} + diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt index e25e3cf923d..956718dcca0 100644 --- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt @@ -378,6 +378,6 @@ "select * from user into outfile s3 'out_file_name'" "unsupported: this construct is not supported on sharded keyspace" -# unsupported two predicates specifying the database for the same table +# unsupported two predicates specifying the database for the same table if they are different "SELECT cc.constraint_name AS 'name' FROM information_schema.check_constraints cc WHERE cc.constraint_schema = 'constraint_schema' AND cc.table_schema = 'a'" "two predicates for specifying the database are not supported"