1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/hanchuanchuan-goInception

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
logical_plan_test.go 62 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
hanchuanchuan Отправлено 5 лет назад 0b68888
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014
// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import (
"fmt"
"sort"
"testing"
"github.com/hanchuanchuan/goInception/ast"
"github.com/hanchuanchuan/goInception/domain"
"github.com/hanchuanchuan/goInception/expression"
"github.com/hanchuanchuan/goInception/infoschema"
"github.com/hanchuanchuan/goInception/model"
"github.com/hanchuanchuan/goInception/mysql"
"github.com/hanchuanchuan/goInception/parser"
"github.com/hanchuanchuan/goInception/sessionctx"
"github.com/hanchuanchuan/goInception/terror"
"github.com/hanchuanchuan/goInception/types"
"github.com/hanchuanchuan/goInception/util/mock"
"github.com/hanchuanchuan/goInception/util/testleak"
. "github.com/pingcap/check"
)
var _ = Suite(&testPlanSuite{})
func TestT(t *testing.T) {
CustomVerboseFlag = true
TestingT(t)
}
type testPlanSuite struct {
*parser.Parser
is infoschema.InfoSchema
ctx sessionctx.Context
}
func (s *testPlanSuite) SetUpSuite(c *C) {
s.is = infoschema.MockInfoSchema([]*model.TableInfo{MockTable()})
s.ctx = mockContext()
s.Parser = parser.New()
}
func newLongType() types.FieldType {
return *(types.NewFieldType(mysql.TypeLong))
}
func newStringType() types.FieldType {
ft := types.NewFieldType(mysql.TypeVarchar)
ft.Charset, ft.Collate = types.DefaultCharsetForType(mysql.TypeVarchar)
return *ft
}
func MockTable() *model.TableInfo {
// column: a, b, c, d, e, c_str, d_str, e_str, f, g
// PK: a
// indeices: c_d_e, e, f, g, f_g, c_d_e_str, c_d_e_str_prefix
indices := []*model.IndexInfo{
{
Name: model.NewCIStr("c_d_e"),
Columns: []*model.IndexColumn{
{
Name: model.NewCIStr("c"),
Length: types.UnspecifiedLength,
Offset: 2,
},
{
Name: model.NewCIStr("d"),
Length: types.UnspecifiedLength,
Offset: 3,
},
{
Name: model.NewCIStr("e"),
Length: types.UnspecifiedLength,
Offset: 4,
},
},
State: model.StatePublic,
Unique: true,
},
{
Name: model.NewCIStr("e"),
Columns: []*model.IndexColumn{
{
Name: model.NewCIStr("e"),
Length: types.UnspecifiedLength,
Offset: 4,
},
},
State: model.StateWriteOnly,
Unique: true,
},
{
Name: model.NewCIStr("f"),
Columns: []*model.IndexColumn{
{
Name: model.NewCIStr("f"),
Length: types.UnspecifiedLength,
Offset: 8,
},
},
State: model.StatePublic,
Unique: true,
},
{
Name: model.NewCIStr("g"),
Columns: []*model.IndexColumn{
{
Name: model.NewCIStr("g"),
Length: types.UnspecifiedLength,
Offset: 9,
},
},
State: model.StatePublic,
},
{
Name: model.NewCIStr("f_g"),
Columns: []*model.IndexColumn{
{
Name: model.NewCIStr("f"),
Length: types.UnspecifiedLength,
Offset: 8,
},
{
Name: model.NewCIStr("g"),
Length: types.UnspecifiedLength,
Offset: 9,
},
},
State: model.StatePublic,
Unique: true,
},
{
Name: model.NewCIStr("c_d_e_str"),
Columns: []*model.IndexColumn{
{
Name: model.NewCIStr("c_str"),
Length: types.UnspecifiedLength,
Offset: 5,
},
{
Name: model.NewCIStr("d_str"),
Length: types.UnspecifiedLength,
Offset: 6,
},
{
Name: model.NewCIStr("e_str"),
Length: types.UnspecifiedLength,
Offset: 7,
},
},
State: model.StatePublic,
},
{
Name: model.NewCIStr("e_d_c_str_prefix"),
Columns: []*model.IndexColumn{
{
Name: model.NewCIStr("e_str"),
Length: types.UnspecifiedLength,
Offset: 7,
},
{
Name: model.NewCIStr("d_str"),
Length: types.UnspecifiedLength,
Offset: 6,
},
{
Name: model.NewCIStr("c_str"),
Length: 10,
Offset: 5,
},
},
State: model.StatePublic,
},
}
pkColumn := &model.ColumnInfo{
State: model.StatePublic,
Offset: 0,
Name: model.NewCIStr("a"),
FieldType: newLongType(),
ID: 1,
}
col0 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 1,
Name: model.NewCIStr("b"),
FieldType: newLongType(),
ID: 2,
}
col1 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 2,
Name: model.NewCIStr("c"),
FieldType: newLongType(),
ID: 3,
}
col2 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 3,
Name: model.NewCIStr("d"),
FieldType: newLongType(),
ID: 4,
}
col3 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 4,
Name: model.NewCIStr("e"),
FieldType: newLongType(),
ID: 5,
}
colStr1 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 5,
Name: model.NewCIStr("c_str"),
FieldType: newStringType(),
ID: 6,
}
colStr2 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 6,
Name: model.NewCIStr("d_str"),
FieldType: newStringType(),
ID: 7,
}
colStr3 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 7,
Name: model.NewCIStr("e_str"),
FieldType: newStringType(),
ID: 8,
}
col4 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 8,
Name: model.NewCIStr("f"),
FieldType: newLongType(),
ID: 9,
}
col5 := &model.ColumnInfo{
State: model.StatePublic,
Offset: 9,
Name: model.NewCIStr("g"),
FieldType: newLongType(),
ID: 10,
}
pkColumn.Flag = mysql.PriKeyFlag | mysql.NotNullFlag
// Column 'b', 'c', 'd', 'f', 'g' is not null.
col0.Flag = mysql.NotNullFlag
col1.Flag = mysql.NotNullFlag
col2.Flag = mysql.NotNullFlag
col4.Flag = mysql.NotNullFlag
col5.Flag = mysql.NotNullFlag
table := &model.TableInfo{
Columns: []*model.ColumnInfo{pkColumn, col0, col1, col2, col3, colStr1, colStr2, colStr3, col4, col5},
Indices: indices,
Name: model.NewCIStr("t"),
PKIsHandle: true,
}
return table
}
func mockContext() sessionctx.Context {
ctx := mock.NewContext()
ctx.Store = &mock.Store{
Client: &mock.Client{},
}
ctx.GetSessionVars().CurrentDB = "test"
do := &domain.Domain{}
do.CreateStatsHandle(ctx)
domain.BindDomain(ctx, do)
return ctx
}
func (s *testPlanSuite) TestPredicatePushDown(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
best string
}{
{
sql: "select count(*) from t a, t b where a.a = b.a",
best: "Join{DataScan(a)->DataScan(b)}(a.a,b.a)->Aggr(count(1))->Projection",
},
{
sql: "select a from (select a from t where d = 0) k where k.a = 5",
best: "DataScan(t)->Projection->Projection",
},
{
sql: "select a from (select a+1 as a from t) k where k.a = 5",
best: "DataScan(t)->Projection->Projection",
},
{
sql: "select a from (select 1+2 as a from t where d = 0) k where k.a = 5",
best: "DataScan(t)->Projection->Projection",
},
{
sql: "select a from (select d as a from t where d = 0) k where k.a = 5",
best: "DataScan(t)->Projection->Projection",
},
{
sql: "select * from t ta, t tb where (ta.d, ta.a) = (tb.b, tb.c)",
best: "Join{DataScan(ta)->DataScan(tb)}(ta.d,tb.b)(ta.a,tb.c)->Projection",
},
{
sql: "select * from t t1, t t2 where t1.a = t2.b and t2.b > 0 and t1.a = t1.c and t1.d like 'abc' and t2.d = t1.d",
best: "Join{DataScan(t2)->Sel([like(cast(t2.d), abc, 92)])->DataScan(t1)->Sel([like(cast(t1.d), abc, 92)])}(t2.b,t1.a)(t2.d,t1.d)->Projection",
},
{
sql: "select * from t ta join t tb on ta.d = tb.d and ta.d > 1 where tb.a = 0",
best: "Join{DataScan(ta)->DataScan(tb)}(ta.d,tb.d)->Projection",
},
{
sql: "select * from t ta join t tb on ta.d = tb.d where ta.d > 1 and tb.a = 0",
best: "Join{DataScan(ta)->DataScan(tb)}(ta.d,tb.d)->Projection",
},
{
sql: "select * from t ta left outer join t tb on ta.d = tb.d and ta.d > 1 where tb.a = 0",
best: "Join{DataScan(ta)->DataScan(tb)}(ta.d,tb.d)->Projection",
},
{
sql: "select * from t ta right outer join t tb on ta.d = tb.d and ta.a > 1 where tb.a = 0",
best: "Join{DataScan(ta)->DataScan(tb)}(ta.d,tb.d)->Projection",
},
{
sql: "select * from t ta left outer join t tb on ta.d = tb.d and ta.a > 1 where ta.d = 0",
best: "Join{DataScan(ta)->DataScan(tb)}->Projection",
},
{
sql: "select * from t ta left outer join t tb on ta.d = tb.d and ta.a > 1 where tb.d = 0",
best: "Join{DataScan(ta)->DataScan(tb)}->Projection",
},
{
sql: "select * from t ta left outer join t tb on ta.d = tb.d and ta.a > 1 where tb.c is not null and tb.c = 0 and ifnull(tb.d, 1)",
best: "Join{DataScan(ta)->DataScan(tb)}(ta.d,tb.d)->Projection",
},
{
sql: "select * from t ta left outer join t tb on ta.a = tb.a left outer join t tc on tb.b = tc.b where tc.c > 0",
best: "Join{Join{DataScan(ta)->DataScan(tb)}(ta.a,tb.a)->DataScan(tc)}(tb.b,tc.b)->Projection",
},
{
sql: "select * from t ta left outer join t tb on ta.a = tb.a left outer join t tc on tc.b = ta.b where tb.c > 0",
best: "Join{Join{DataScan(ta)->DataScan(tb)}(ta.a,tb.a)->DataScan(tc)}(ta.b,tc.b)->Projection",
},
{
sql: "select * from t as ta left outer join (t as tb left join t as tc on tc.b = tb.b) on tb.a = ta.a where tc.c > 0",
best: "Join{DataScan(ta)->Join{DataScan(tb)->DataScan(tc)}(tb.b,tc.b)}(ta.a,tb.a)->Projection",
},
{
sql: "select * from ( t as ta left outer join t as tb on ta.a = tb.a) join ( t as tc left join t as td on tc.b = td.b) on ta.c = td.c where tb.c = 2 and td.a = 1",
best: "Join{Join{DataScan(ta)->DataScan(tb)}(ta.a,tb.a)->Join{DataScan(tc)->DataScan(td)}(tc.b,td.b)}(ta.c,td.c)->Projection",
},
{
sql: "select * from t ta left outer join (t tb left outer join t tc on tc.b = tb.b) on tb.a = ta.a and tc.c = ta.c where tc.d > 0 or ta.d > 0",
best: "Join{DataScan(ta)->Join{DataScan(tb)->DataScan(tc)}(tb.b,tc.b)}(ta.a,tb.a)(ta.c,tc.c)->Sel([or(gt(tc.d, 0), gt(ta.d, 0))])->Projection",
},
{
sql: "select * from t ta left outer join t tb on ta.d = tb.d and ta.a > 1 where ifnull(tb.d, null) or tb.d is null",
best: "Join{DataScan(ta)->DataScan(tb)}(ta.d,tb.d)->Sel([or(ifnull(tb.d, <nil>), isnull(tb.d))])->Projection",
},
{
sql: "select a, d from (select * from t union all select * from t union all select * from t) z where a < 10",
best: "UnionAll{DataScan(t)->Projection->Projection->DataScan(t)->Projection->Projection->DataScan(t)->Projection->Projection}->Projection",
},
{
sql: "select (select count(*) from t where t.a = k.a) from t k",
best: "Apply{DataScan(k)->DataScan(t)->Aggr(count(1))->Projection->MaxOneRow}->Projection",
},
{
sql: "select a from t where exists(select 1 from t as x where x.a < t.a)",
best: "Join{DataScan(t)->DataScan(x)}->Projection",
},
{
sql: "select a from t where exists(select 1 from t as x where x.a = t.a and t.a < 1 and x.a < 1)",
best: "Join{DataScan(t)->DataScan(x)}(test.t.a,x.a)->Projection",
},
{
sql: "select a from t where exists(select 1 from t as x where x.a = t.a and x.a < 1) and a < 1",
best: "Join{DataScan(t)->DataScan(x)}(test.t.a,x.a)->Projection",
},
{
sql: "select a from t where exists(select 1 from t as x where x.a = t.a) and exists(select 1 from t as x where x.a = t.a)",
best: "Join{Join{DataScan(t)->DataScan(x)}(test.t.a,x.a)->DataScan(x)}(test.t.a,x.a)->Projection",
},
{
sql: "select * from (select a, b, sum(c) as s from t group by a, b) k where k.a > k.b * 2 + 1",
best: "DataScan(t)->Aggr(sum(test.t.c),firstrow(test.t.a),firstrow(test.t.b))->Projection->Projection",
},
{
sql: "select * from (select a, b, sum(c) as s from t group by a, b) k where k.a > 1 and k.b > 2",
best: "DataScan(t)->Aggr(sum(test.t.c),firstrow(test.t.a),firstrow(test.t.b))->Projection->Projection",
},
{
sql: "select * from (select k.a, sum(k.s) as ss from (select a, sum(b) as s from t group by a) k group by k.a) l where l.a > 2",
best: "DataScan(t)->Aggr(sum(test.t.b),firstrow(test.t.a))->Projection->Aggr(sum(k.s),firstrow(k.a))->Projection->Projection",
},
{
sql: "select * from (select a, sum(b) as s from t group by a) k where a > s",
best: "DataScan(t)->Aggr(sum(test.t.b),firstrow(test.t.a))->Sel([gt(cast(test.t.a), 2_col_0)])->Projection->Projection",
},
{
sql: "select * from (select a, sum(b) as s from t group by a + 1) k where a > 1",
best: "DataScan(t)->Aggr(sum(test.t.b),firstrow(test.t.a))->Sel([gt(test.t.a, 1)])->Projection->Projection",
},
{
sql: "select * from (select a, sum(b) as s from t group by a having 1 = 0) k where a > 1",
best: "Dual->Sel([gt(k.a, 1)])->Projection",
},
{
sql: "select a, count(a) cnt from t group by a having cnt < 1",
best: "DataScan(t)->Aggr(count(test.t.a),firstrow(test.t.a))->Sel([lt(2_col_0, 1)])->Projection",
},
// issue #3873
{
sql: "select t1.a, t2.a from t as t1 left join t as t2 on t1.a = t2.a where t1.a < 1.0",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.a,t2.a)->Projection",
},
// issue #7728
{
sql: "select * from t t1 join t t2 on t1.a = t2.a where t2.a = null",
best: "Dual->Projection",
},
}
for _, ca := range tests {
comment := Commentf("for %s", ca.sql)
stmt, err := s.ParseOneStmt(ca.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
p, err = logicalOptimize(flagPredicatePushDown|flagDecorrelate|flagPrunColumns, p.(LogicalPlan))
c.Assert(err, IsNil)
c.Assert(ToString(p), Equals, ca.best, Commentf("for %s", ca.sql))
}
}
func (s *testPlanSuite) TestJoinPredicatePushDown(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
left string
right string
}{
// issue #7628, inner join
{
sql: "select * from t as t1 join t as t2 on t1.b = t2.b where t1.a > t2.a",
left: "[]",
right: "[]",
},
{
sql: "select * from t as t1 join t as t2 on t1.b = t2.b where t1.a=1 or t2.a=1",
left: "[]",
right: "[]",
},
{
sql: "select * from t as t1 join t as t2 on t1.b = t2.b where (t1.a=1 and t2.a=1) or (t1.a=2 and t2.a=2)",
left: "[or(eq(t1.a, 1), eq(t1.a, 2))]",
right: "[or(eq(t2.a, 1), eq(t2.a, 2))]",
},
{
sql: "select * from t as t1 join t as t2 on t1.b = t2.b where (t1.c=1 and (t1.a=3 or t2.a=3)) or (t1.a=2 and t2.a=2)",
left: "[or(eq(t1.c, 1), eq(t1.a, 2))]",
right: "[]",
},
{
sql: "select * from t as t1 join t as t2 on t1.b = t2.b where (t1.c=1 and ((t1.a=3 and t2.a=3) or (t1.a=4 and t2.a=4)))",
left: "[eq(t1.c, 1) or(eq(t1.a, 3), eq(t1.a, 4))]",
right: "[or(eq(t2.a, 3), eq(t2.a, 4))]",
},
{
sql: "select * from t as t1 join t as t2 on t1.b = t2.b where (t1.a>1 and t1.a < 3 and t2.a=1) or (t1.a=2 and t2.a=2)",
left: "[or(and(gt(t1.a, 1), lt(t1.a, 3)), eq(t1.a, 2))]",
right: "[or(eq(t2.a, 1), eq(t2.a, 2))]",
},
{
sql: "select * from t as t1 join t as t2 on t1.b = t2.b and ((t1.a=1 and t2.a=1) or (t1.a=2 and t2.a=2))",
left: "[or(eq(t1.a, 1), eq(t1.a, 2))]",
right: "[or(eq(t2.a, 1), eq(t2.a, 2))]",
},
// issue #7628, left join
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b and ((t1.a=1 and t2.a=1) or (t1.a=2 and t2.a=2))",
left: "[]",
right: "[or(eq(t2.a, 1), eq(t2.a, 2))]",
},
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b and t1.a > t2.a",
left: "[]",
right: "[]",
},
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b and (t1.a=1 or t2.a=1)",
left: "[]",
right: "[]",
},
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b and ((t1.c=1 and (t1.a=3 or t2.a=3)) or (t1.a=2 and t2.a=2))",
left: "[]",
right: "[]",
},
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b and ((t2.c=1 and (t1.a=3 or t2.a=3)) or (t1.a=2 and t2.a=2))",
left: "[]",
right: "[or(eq(t2.c, 1), eq(t2.a, 2))]",
},
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b and ((t1.c=1 and ((t1.a=3 and t2.a=3) or (t1.a=4 and t2.a=4))) or (t1.a=2 and t2.a=2))",
left: "[]",
right: "[or(or(eq(t2.a, 3), eq(t2.a, 4)), eq(t2.a, 2))]",
},
}
for _, ca := range tests {
comment := Commentf("for %s", ca.sql)
stmt, err := s.ParseOneStmt(ca.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil, comment)
p, err = logicalOptimize(flagPredicatePushDown|flagDecorrelate|flagPrunColumns, p.(LogicalPlan))
c.Assert(err, IsNil, comment)
proj, ok := p.(*LogicalProjection)
c.Assert(ok, IsTrue, comment)
join, ok := proj.children[0].(*LogicalJoin)
c.Assert(ok, IsTrue, comment)
leftPlan, ok := join.children[0].(*DataSource)
c.Assert(ok, IsTrue, comment)
rightPlan, ok := join.children[1].(*DataSource)
c.Assert(ok, IsTrue, comment)
leftCond := fmt.Sprintf("%s", leftPlan.pushedDownConds)
rightCond := fmt.Sprintf("%s", rightPlan.pushedDownConds)
c.Assert(leftCond, Equals, ca.left, comment)
c.Assert(rightCond, Equals, ca.right, comment)
}
}
func (s *testPlanSuite) TestOuterWherePredicatePushDown(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
sel string
left string
right string
}{
// issue #7628, left join with where condition
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b where (t1.a=1 and t2.a is null) or (t1.a=2 and t2.a=2)",
sel: "[or(and(eq(t1.a, 1), isnull(t2.a)), and(eq(t1.a, 2), eq(t2.a, 2)))]",
left: "[or(eq(t1.a, 1), eq(t1.a, 2))]",
right: "[]",
},
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b where (t1.c=1 and (t1.a=3 or t2.a=3)) or (t1.a=2 and t2.a=2)",
sel: "[or(and(eq(t1.c, 1), or(eq(t1.a, 3), eq(t2.a, 3))), and(eq(t1.a, 2), eq(t2.a, 2)))]",
left: "[or(eq(t1.c, 1), eq(t1.a, 2))]",
right: "[]",
},
{
sql: "select * from t as t1 left join t as t2 on t1.b = t2.b where (t1.c=1 and ((t1.a=3 and t2.a=3) or (t1.a=4 and t2.a=4))) or (t1.a=2 and t2.a is null)",
sel: "[or(and(eq(t1.c, 1), or(and(eq(t1.a, 3), eq(t2.a, 3)), and(eq(t1.a, 4), eq(t2.a, 4)))), and(eq(t1.a, 2), isnull(t2.a)))]",
left: "[or(and(eq(t1.c, 1), or(eq(t1.a, 3), eq(t1.a, 4))), eq(t1.a, 2))]",
right: "[]",
},
}
for _, ca := range tests {
comment := Commentf("for %s", ca.sql)
stmt, err := s.ParseOneStmt(ca.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil, comment)
p, err = logicalOptimize(flagPredicatePushDown|flagDecorrelate|flagPrunColumns, p.(LogicalPlan))
c.Assert(err, IsNil, comment)
proj, ok := p.(*LogicalProjection)
c.Assert(ok, IsTrue, comment)
selection, ok := proj.children[0].(*LogicalSelection)
c.Assert(ok, IsTrue, comment)
selCond := fmt.Sprintf("%s", selection.Conditions)
c.Assert(selCond, Equals, ca.sel, comment)
join, ok := selection.children[0].(*LogicalJoin)
c.Assert(ok, IsTrue, comment)
leftPlan, ok := join.children[0].(*DataSource)
c.Assert(ok, IsTrue, comment)
rightPlan, ok := join.children[1].(*DataSource)
c.Assert(ok, IsTrue, comment)
leftCond := fmt.Sprintf("%s", leftPlan.pushedDownConds)
rightCond := fmt.Sprintf("%s", rightPlan.pushedDownConds)
c.Assert(leftCond, Equals, ca.left, comment)
c.Assert(rightCond, Equals, ca.right, comment)
}
}
func (s *testPlanSuite) TestSimplifyOuterJoin(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
best string
joinType string
}{
{
sql: "select * from t t1 left join t t2 on t1.b = t2.b where t1.c > 1 or t2.c > 1;",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.b,t2.b)->Sel([or(gt(t1.c, 1), gt(t2.c, 1))])->Projection",
joinType: "left outer join",
},
{
sql: "select * from t t1 left join t t2 on t1.b = t2.b where t1.c > 1 and t2.c > 1;",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.b,t2.b)->Projection",
joinType: "inner join",
},
{
sql: "select * from t t1 left join t t2 on t1.b = t2.b where not (t1.c > 1 or t2.c > 1);",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.b,t2.b)->Projection",
joinType: "inner join",
},
{
sql: "select * from t t1 left join t t2 on t1.b = t2.b where not (t1.c > 1 and t2.c > 1);",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.b,t2.b)->Sel([not(and(le(t1.c, 1), le(t2.c, 1)))])->Projection",
joinType: "left outer join",
},
{
sql: "select * from t t1 left join t t2 on t1.b > 1 where t1.c = t2.c;",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.c,t2.c)->Projection",
joinType: "inner join",
},
{
sql: "select * from t t1 left join t t2 on true where t1.b <=> t2.b;",
best: "Join{DataScan(t1)->DataScan(t2)}->Sel([nulleq(t1.b, t2.b)])->Projection",
joinType: "left outer join",
},
}
for _, ca := range tests {
comment := Commentf("for %s", ca.sql)
stmt, err := s.ParseOneStmt(ca.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil, comment)
p, err = logicalOptimize(flagPredicatePushDown|flagPrunColumns, p.(LogicalPlan))
c.Assert(err, IsNil, comment)
c.Assert(ToString(p), Equals, ca.best, comment)
join, ok := p.(LogicalPlan).Children()[0].(*LogicalJoin)
if !ok {
join, ok = p.(LogicalPlan).Children()[0].Children()[0].(*LogicalJoin)
c.Assert(ok, IsTrue, comment)
}
joinType := fmt.Sprintf("%s", join.JoinType.String())
c.Assert(joinType, Equals, ca.joinType, comment)
}
}
func newPartitionInfoSchema(definitions []model.PartitionDefinition) infoschema.InfoSchema {
tableInfo := *MockTable()
cols := make([]*model.ColumnInfo, 0, len(tableInfo.Columns))
cols = append(cols, tableInfo.Columns...)
cols = append(cols, &model.ColumnInfo{
State: model.StatePublic,
Offset: 10,
Name: model.NewCIStr("h"),
FieldType: newLongType(),
ID: 11,
})
partition := &model.PartitionInfo{
Type: model.PartitionTypeRange,
Expr: "h",
Enable: true,
Definitions: definitions,
}
tableInfo.Columns = cols
tableInfo.Partition = partition
is := infoschema.MockInfoSchema([]*model.TableInfo{&tableInfo})
return is
}
func (s *testPlanSuite) TestTablePartition(c *C) {
defer testleak.AfterTest(c)()
definitions := []model.PartitionDefinition{
{
ID: 41,
Name: model.NewCIStr("p1"),
LessThan: []string{"16"},
},
{
ID: 42,
Name: model.NewCIStr("p2"),
LessThan: []string{"32"},
},
{
ID: 43,
Name: model.NewCIStr("p3"),
LessThan: []string{"64"},
},
{
ID: 44,
Name: model.NewCIStr("p4"),
LessThan: []string{"128"},
},
{
ID: 45,
Name: model.NewCIStr("p5"),
LessThan: []string{"maxvalue"},
},
}
is := newPartitionInfoSchema(definitions)
// is1 equals to is without maxvalue partition.
definitions1 := make([]model.PartitionDefinition, len(definitions)-1)
copy(definitions1, definitions)
is1 := newPartitionInfoSchema(definitions1)
tests := []struct {
sql string
first string
best string
is infoschema.InfoSchema
}{
{
sql: "select * from t",
best: "UnionAll{Partition(41)->Partition(42)->Partition(43)->Partition(44)->Partition(45)}->Projection",
is: is,
},
{
sql: "select * from t where t.h < 31",
best: "UnionAll{Partition(41)->Partition(42)}->Projection",
is: is,
},
{
sql: "select * from t where t.h < 61",
best: "UnionAll{Partition(41)->Partition(42)->Partition(43)}->Projection",
is: is,
},
{
sql: "select * from t where t.h > 17 and t.h < 61",
best: "UnionAll{Partition(42)->Partition(43)}->Projection",
is: is,
},
{
sql: "select * from t where t.h < 8",
best: "Partition(41)->Projection",
is: is,
},
{
sql: "select * from t where t.h > 128",
best: "Partition(45)->Projection",
is: is,
},
{
sql: "select * from t where t.h > 128",
best: "Dual->Projection",
is: is1,
},
{
// NULL will be located in the first partition.
sql: "select * from t where t.h is null",
best: "Partition(41)->Projection",
is: is,
},
{
sql: "select * from t where t.h is null or t.h > 70",
best: "UnionAll{Partition(41)->Partition(44)}->Projection",
is: is1,
},
}
for _, ca := range tests {
comment := Commentf("for %s", ca.sql)
stmt, err := s.ParseOneStmt(ca.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, ca.is)
c.Assert(err, IsNil)
p, err = logicalOptimize(flagDecorrelate|flagPrunColumns|flagPredicatePushDown|flagPartitionProcessor, p.(LogicalPlan))
c.Assert(err, IsNil)
c.Assert(ToString(p), Equals, ca.best, Commentf("for %s", ca.sql))
}
}
func (s *testPlanSuite) TestSubquery(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
best string
}{
{
// This will be resolved as in sub query.
sql: "select * from t where 10 in (select b from t s where s.a = t.a)",
best: "Join{DataScan(t)->DataScan(s)}(test.t.a,s.a)->Projection",
},
{
sql: "select count(c) ,(select b from t s where s.a = t.a) from t",
best: "Join{DataScan(t)->Aggr(count(test.t.c),firstrow(test.t.a))->DataScan(s)}(test.t.a,s.a)->Projection->Projection",
},
{
sql: "select count(c) ,(select count(s.b) from t s where s.a = t.a) from t",
best: "Join{DataScan(t)->Aggr(count(test.t.c),firstrow(test.t.a))->DataScan(s)}(test.t.a,s.a)->Aggr(firstrow(2_col_0),firstrow(test.t.a),count(s.b))->Projection->Projection",
},
{
// Semi-join with agg cannot decorrelate.
sql: "select t.c in (select count(s.b) from t s where s.a = t.a) from t",
best: "Apply{DataScan(t)->DataScan(s)->Sel([eq(s.a, test.t.a)])->Aggr(count(s.b))}->Projection",
},
{
sql: "select (select count(s.b) k from t s where s.a = t.a having k != 0) from t",
best: "Join{DataScan(t)->DataScan(s)->Aggr(count(s.b),firstrow(s.a))}(test.t.a,s.a)->Projection->Projection->Projection",
},
{
sql: "select (select count(s.b) k from t s where s.a = t1.a) from t t1, t t2",
best: "Join{Join{DataScan(t1)->DataScan(t2)}->DataScan(s)->Aggr(count(s.b),firstrow(s.a))}(t1.a,s.a)->Projection->Projection->Projection",
},
{
sql: "select (select count(1) k from t s where s.a = t.a having k != 0) from t",
best: "Join{DataScan(t)->DataScan(s)->Aggr(count(1),firstrow(s.a))}(test.t.a,s.a)->Projection->Projection->Projection",
},
{
sql: "select a from t where a in (select a from t s group by t.b)",
best: "Join{DataScan(t)->DataScan(s)->Aggr(firstrow(s.a))->Projection}(test.t.a,s.a)->Projection",
},
{
// This will be resolved as in sub query.
sql: "select * from t where 10 in (((select b from t s where s.a = t.a)))",
best: "Join{DataScan(t)->DataScan(s)}(test.t.a,s.a)->Projection",
},
{
// This will be resolved as in function.
sql: "select * from t where 10 in (((select b from t s where s.a = t.a)), 10)",
best: "Join{DataScan(t)->DataScan(s)}(test.t.a,s.a)->Projection->Sel([in(10, s.b, 10)])->Projection",
},
{
sql: "select * from t where exists (select s.a from t s having sum(s.a) = t.a )",
best: "Join{DataScan(t)->DataScan(s)->Aggr(sum(s.a))->Projection}->Projection",
},
{
// Test MaxOneRow for limit.
sql: "select (select * from (select b from t limit 1) x where x.b = t1.b) from t t1",
best: "Join{DataScan(t1)->DataScan(t)->Projection->Limit}(t1.b,x.b)->Projection->Projection",
},
{
// Test Nested sub query.
sql: "select * from t where exists (select s.a from t s where s.c in (select c from t as k where k.d = s.d) having sum(s.a) = t.a )",
best: "Join{DataScan(t)->Join{DataScan(s)->DataScan(k)}(s.d,k.d)(s.c,k.c)->Aggr(sum(s.a))->Projection}->Projection",
},
{
sql: "select t1.b from t t1 where t1.b = (select max(t2.a) from t t2 where t1.b=t2.b)",
best: "Join{DataScan(t1)->DataScan(t2)->Aggr(max(t2.a),firstrow(t2.b))}(t1.b,t2.b)->Projection->Sel([eq(t1.b, max(t2.a))])->Projection",
},
{
sql: "select t1.b from t t1 where t1.b = (select avg(t2.a) from t t2 where t1.g=t2.g and (t1.b = 4 or t2.b = 2))",
best: "Apply{DataScan(t1)->DataScan(t2)->Sel([eq(t1.g, t2.g) or(eq(t1.b, 4), eq(t2.b, 2))])->Aggr(avg(t2.a))}->Projection->Sel([eq(cast(t1.b), avg(t2.a))])->Projection",
},
}
for _, ca := range tests {
comment := Commentf("for %s", ca.sql)
stmt, err := s.ParseOneStmt(ca.sql, "", "")
c.Assert(err, IsNil, comment)
Preprocess(s.ctx, stmt, s.is, false)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
if lp, ok := p.(LogicalPlan); ok {
p, err = logicalOptimize(flagBuildKeyInfo|flagDecorrelate|flagPrunColumns, lp)
c.Assert(err, IsNil)
}
c.Assert(ToString(p), Equals, ca.best, Commentf("for %s", ca.sql))
}
}
func (s *testPlanSuite) TestPlanBuilder(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
plan string
}{
{
sql: "select * from t for update",
plan: "DataScan(t)->Lock->Projection",
},
{
sql: "update t set t.a = t.a * 1.5 where t.a >= 1000 order by t.a desc limit 10",
plan: "TableReader(Table(t)->Limit)->Limit->Update",
},
{
sql: "delete from t where t.a >= 1000 order by t.a desc limit 10",
plan: "TableReader(Table(t)->Limit)->Limit->Delete",
},
{
sql: "explain select * from t union all select * from t limit 1, 1",
plan: "*core.Explain",
},
// The correctness of explain result is checked at integration test. There is to improve coverage.
{
sql: "explain select /*+ TIDB_INLJ(t1, t2) */ * from t t1 left join t t2 on t1.a=t2.a where t1.b=1 and t2.b=1 and (t1.c=1 or t2.c=1)",
plan: "*core.Explain",
},
{
sql: "explain select /*+ TIDB_HJ(t1, t2) */ * from t t1 left join t t2 on t1.a=t2.a where t1.b=1 and t2.b=1 and (t1.c=1 or t2.c=1)",
plan: "*core.Explain",
},
{
sql: "explain select /*+ TIDB_SMJ(t1, t2) */ * from t t1 right join t t2 on t1.a=t2.a where t1.b=1 and t2.b=1 and (t1.c=1 or t2.c=1)",
plan: "*core.Explain",
},
{
sql: `explain format="dot" select /*+ TIDB_SMJ(t1, t2) */ * from t t1, t t2 where t1.a=t2.a`,
plan: "*core.Explain",
},
{
sql: "explain select * from t order by b",
plan: "*core.Explain",
},
{
sql: "explain select * from t order by b limit 1",
plan: "*core.Explain",
},
{
sql: `explain format="dot" select * from t order by a`,
plan: "*core.Explain",
},
{
sql: "insert into t select * from t",
plan: "TableReader(Table(t))->Insert",
},
{
sql: "show columns from t where `Key` = 'pri' like 't*'",
plan: "Show([eq(cast(key), 0)])",
},
{
sql: "do sleep(5)",
plan: "Dual->Projection",
},
{
sql: "select substr(\"abc\", 1)",
plan: "Dual->Projection",
},
{
sql: "select * from t t1, t t2 where 1 = 0",
plan: "Dual->Projection",
},
{
sql: "select * from t t1 join t t2 using(a)",
plan: "Join{DataScan(t1)->DataScan(t2)}->Projection",
},
{
sql: "select * from t t1 natural join t t2",
plan: "Join{DataScan(t1)->DataScan(t2)}->Projection",
},
}
for _, ca := range tests {
comment := Commentf("for %s", ca.sql)
stmt, err := s.ParseOneStmt(ca.sql, "", "")
c.Assert(err, IsNil, comment)
s.ctx.GetSessionVars().HashJoinConcurrency = 1
Preprocess(s.ctx, stmt, s.is, false)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
if lp, ok := p.(LogicalPlan); ok {
p, err = logicalOptimize(flagPrunColumns, lp)
c.Assert(err, IsNil)
}
c.Assert(ToString(p), Equals, ca.plan, Commentf("for %s", ca.sql))
}
}
func (s *testPlanSuite) TestJoinReOrder(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
best string
}{
{
sql: "select * from t t1, t t2, t t3, t t4, t t5, t t6 where t1.a = t2.b and t2.a = t3.b and t3.c = t4.a and t4.d = t2.c and t5.d = t6.d",
best: "Join{Join{Join{Join{DataScan(t1)->DataScan(t2)}(t1.a,t2.b)->DataScan(t3)}(t2.a,t3.b)->DataScan(t4)}(t3.c,t4.a)(t2.c,t4.d)->Join{DataScan(t5)->DataScan(t6)}(t5.d,t6.d)}->Projection",
},
{
sql: "select * from t t1, t t2, t t3, t t4, t t5, t t6, t t7, t t8 where t1.a = t8.a",
best: "Join{Join{Join{Join{DataScan(t1)->DataScan(t8)}(t1.a,t8.a)->DataScan(t2)}->Join{DataScan(t3)->DataScan(t4)}}->Join{Join{DataScan(t5)->DataScan(t6)}->DataScan(t7)}}->Projection",
},
{
sql: "select * from t t1, t t2, t t3, t t4, t t5 where t1.a = t5.a and t5.a = t4.a and t4.a = t3.a and t3.a = t2.a and t2.a = t1.a and t1.a = t3.a and t2.a = t4.a and t5.b < 8",
best: "Join{Join{Join{Join{DataScan(t5)->DataScan(t1)}(t5.a,t1.a)->DataScan(t2)}(t1.a,t2.a)->DataScan(t3)}(t2.a,t3.a)(t1.a,t3.a)->DataScan(t4)}(t5.a,t4.a)(t3.a,t4.a)(t2.a,t4.a)->Projection",
},
{
sql: "select * from t t1, t t2, t t3, t t4, t t5 where t1.a = t5.a and t5.a = t4.a and t4.a = t3.a and t3.a = t2.a and t2.a = t1.a and t1.a = t3.a and t2.a = t4.a and t3.b = 1 and t4.a = 1",
best: "Join{Join{Join{Join{DataScan(t3)->DataScan(t4)}->DataScan(t5)}->DataScan(t1)}->DataScan(t2)}->Projection",
},
{
sql: "select * from t o where o.b in (select t3.c from t t1, t t2, t t3 where t1.a = t3.a and t2.a = t3.a and t2.a = o.a)",
best: "Apply{DataScan(o)->Join{Join{DataScan(t2)->DataScan(t3)}(t2.a,t3.a)->DataScan(t1)}(t3.a,t1.a)->Projection}->Projection",
},
{
sql: "select * from t o where o.b in (select t3.c from t t1, t t2, t t3 where t1.a = t3.a and t2.a = t3.a and t2.a = o.a and t1.a = 1)",
best: "Apply{DataScan(o)->Join{Join{DataScan(t1)->DataScan(t3)}->DataScan(t2)}->Projection}->Projection",
},
}
for _, tt := range tests {
comment := Commentf("for %s", tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
p, err = logicalOptimize(flagPredicatePushDown, p.(LogicalPlan))
c.Assert(err, IsNil)
c.Assert(ToString(p), Equals, tt.best, Commentf("for %s", tt.sql))
}
}
func (s *testPlanSuite) TestEagerAggregation(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
best string
}{
{
sql: "select sum(t.a), sum(t.a+1), sum(t.a), count(t.a), sum(t.a) + count(t.a) from t",
best: "DataScan(t)->Aggr(sum(test.t.a),sum(plus(test.t.a, 1)),count(test.t.a))->Projection",
},
{
sql: "select sum(t.a + t.b), sum(t.a + t.c), sum(t.a + t.b), count(t.a) from t having sum(t.a + t.b) > 0 order by sum(t.a + t.c)",
best: "DataScan(t)->Aggr(sum(plus(test.t.a, test.t.b)),sum(plus(test.t.a, test.t.c)),count(test.t.a))->Sel([gt(2_col_0, 0)])->Projection->Sort->Projection",
},
{
sql: "select sum(a.a) from t a, t b where a.c = b.c",
best: "Join{DataScan(a)->Aggr(sum(a.a),firstrow(a.c))->DataScan(b)}(a.c,b.c)->Aggr(sum(join_agg_0))->Projection",
},
{
sql: "select sum(b.a) from t a, t b where a.c = b.c",
best: "Join{DataScan(a)->DataScan(b)->Aggr(sum(b.a),firstrow(b.c))}(a.c,b.c)->Aggr(sum(join_agg_0))->Projection",
},
{
sql: "select sum(b.a), a.a from t a, t b where a.c = b.c",
best: "Join{DataScan(a)->DataScan(b)->Aggr(sum(b.a),firstrow(b.c))}(a.c,b.c)->Aggr(sum(join_agg_0),firstrow(a.a))->Projection",
},
{
sql: "select sum(a.a), b.a from t a, t b where a.c = b.c",
best: "Join{DataScan(a)->Aggr(sum(a.a),firstrow(a.c))->DataScan(b)}(a.c,b.c)->Aggr(sum(join_agg_0),firstrow(b.a))->Projection",
},
{
sql: "select sum(a.a), sum(b.a) from t a, t b where a.c = b.c",
best: "Join{DataScan(a)->DataScan(b)}(a.c,b.c)->Aggr(sum(a.a),sum(b.a))->Projection",
},
{
sql: "select sum(a.a), max(b.a) from t a, t b where a.c = b.c",
best: "Join{DataScan(a)->Aggr(sum(a.a),firstrow(a.c))->DataScan(b)}(a.c,b.c)->Aggr(sum(join_agg_0),max(b.a))->Projection",
},
{
sql: "select max(a.a), sum(b.a) from t a, t b where a.c = b.c",
best: "Join{DataScan(a)->DataScan(b)->Aggr(sum(b.a),firstrow(b.c))}(a.c,b.c)->Aggr(max(a.a),sum(join_agg_0))->Projection",
},
{
sql: "select sum(a.a) from t a, t b, t c where a.c = b.c and b.c = c.c",
best: "Join{Join{DataScan(a)->DataScan(b)}(a.c,b.c)->DataScan(c)}(b.c,c.c)->Aggr(sum(a.a))->Projection",
},
{
sql: "select sum(b.a) from t a left join t b on a.c = b.c",
best: "Join{DataScan(a)->DataScan(b)->Aggr(sum(b.a),firstrow(b.c))}(a.c,b.c)->Aggr(sum(join_agg_0))->Projection",
},
{
sql: "select sum(a.a) from t a left join t b on a.c = b.c",
best: "Join{DataScan(a)->Aggr(sum(a.a),firstrow(a.c))->DataScan(b)}(a.c,b.c)->Aggr(sum(join_agg_0))->Projection",
},
{
sql: "select sum(a.a) from t a right join t b on a.c = b.c",
best: "Join{DataScan(a)->Aggr(sum(a.a),firstrow(a.c))->DataScan(b)}(a.c,b.c)->Aggr(sum(join_agg_0))->Projection",
},
{
sql: "select sum(a) from (select * from t) x",
best: "DataScan(t)->Aggr(sum(test.t.a))->Projection",
},
{
sql: "select sum(c1) from (select c c1, d c2 from t a union all select a c1, b c2 from t b union all select b c1, e c2 from t c) x group by c2",
best: "UnionAll{DataScan(a)->Projection->Aggr(sum(a.c1),firstrow(a.c2))->DataScan(b)->Projection->Aggr(sum(b.c1),firstrow(b.c2))->DataScan(c)->Projection->Aggr(sum(c.c1),firstrow(c.c2))}->Aggr(sum(join_agg_0))->Projection",
},
{
sql: "select max(a.b), max(b.b) from t a join t b on a.c = b.c group by a.a",
best: "Join{DataScan(a)->DataScan(b)->Aggr(max(b.b),firstrow(b.c))}(a.c,b.c)->Projection->Projection",
},
{
sql: "select max(a.b), max(b.b) from t a join t b on a.a = b.a group by a.c",
best: "Join{DataScan(a)->DataScan(b)}(a.a,b.a)->Aggr(max(a.b),max(b.b))->Projection",
},
{
sql: "select max(c.b) from (select * from t a union all select * from t b) c group by c.a",
best: "UnionAll{DataScan(a)->Projection->Projection->Projection->DataScan(b)->Projection->Projection->Projection}->Aggr(max(join_agg_0))->Projection",
},
{
sql: "select max(a.c) from t a join t b on a.a=b.a and a.b=b.b group by a.b",
best: "Join{DataScan(a)->DataScan(b)}(a.a,b.a)(a.b,b.b)->Aggr(max(a.c))->Projection",
},
{
sql: "select t1.a, count(t2.b) from t t1, t t2 where t1.a = t2.a group by t1.a",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.a,t2.a)->Projection->Projection",
},
}
s.ctx.GetSessionVars().AllowAggPushDown = true
for _, tt := range tests {
comment := Commentf("for %s", tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
p, err = logicalOptimize(flagBuildKeyInfo|flagPredicatePushDown|flagPrunColumns|flagPushDownAgg, p.(LogicalPlan))
c.Assert(err, IsNil)
c.Assert(ToString(p), Equals, tt.best, Commentf("for %s", tt.sql))
}
s.ctx.GetSessionVars().AllowAggPushDown = false
}
func (s *testPlanSuite) TestColumnPruning(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
ans map[int][]string
}{
{
sql: "select count(*) from t group by a",
ans: map[int][]string{
1: {"a"},
},
},
{
sql: "select count(*) from t",
ans: map[int][]string{
1: {},
},
},
{
sql: "select count(*) from t a join t b where a.a < 1",
ans: map[int][]string{
1: {"a"},
2: {},
},
},
{
sql: "select count(*) from t a join t b on a.a = b.d",
ans: map[int][]string{
1: {"a"},
2: {"d"},
},
},
{
sql: "select count(*) from t a join t b on a.a = b.d order by sum(a.d)",
ans: map[int][]string{
1: {"a", "d"},
2: {"d"},
},
},
{
sql: "select count(b.a) from t a join t b on a.a = b.d group by b.b order by sum(a.d)",
ans: map[int][]string{
1: {"a", "d"},
2: {"a", "b", "d"},
},
},
{
sql: "select * from (select count(b.a) from t a join t b on a.a = b.d group by b.b having sum(a.d) < 0) tt",
ans: map[int][]string{
1: {"a", "d"},
2: {"a", "b", "d"},
},
},
{
sql: "select (select count(a) from t where b = k.a) from t k",
ans: map[int][]string{
1: {"a"},
3: {"a", "b"},
},
},
{
sql: "select exists (select count(*) from t where b = k.a) from t k",
ans: map[int][]string{
1: {},
},
},
{
sql: "select b = (select count(*) from t where b = k.a) from t k",
ans: map[int][]string{
1: {"a", "b"},
3: {"b"},
},
},
{
sql: "select exists (select count(a) from t where b = k.a group by b) from t k",
ans: map[int][]string{
1: {"a"},
3: {"b"},
},
},
{
sql: "select a as c1, b as c2 from t order by 1, c1 + c2 + c",
ans: map[int][]string{
1: {"a", "b", "c"},
},
},
{
sql: "select a from t where b < any (select c from t)",
ans: map[int][]string{
1: {"a", "b"},
3: {"c"},
},
},
{
sql: "select a from t where (b,a) != all (select c,d from t)",
ans: map[int][]string{
1: {"a", "b"},
3: {"c", "d"},
},
},
{
sql: "select a from t where (b,a) in (select c,d from t)",
ans: map[int][]string{
1: {"a", "b"},
3: {"c", "d"},
},
},
{
sql: "select a from t where a in (select a from t s group by t.b)",
ans: map[int][]string{
1: {"a"},
3: {"a"},
},
},
//issue 7833
// {
// sql: "drop view if exists v",
// ans: map[int][]string{
// 1: {},
// },
// },
}
for _, tt := range tests {
comment := Commentf("for %s", tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
if plan, ok := p.(LogicalPlan); ok {
lp, err := logicalOptimize(flagPredicatePushDown|flagPrunColumns, plan)
c.Assert(err, IsNil)
checkDataSourceCols(lp, c, tt.ans, comment)
} else {
c.Assert(ok, Equals, true, Commentf("%#v", p))
}
}
}
func (s *testPlanSuite) TestAllocID(c *C) {
ctx := mockContext()
pA := DataSource{}.init(ctx)
pB := DataSource{}.init(ctx)
c.Assert(pA.id+1, Equals, pB.id)
}
func checkDataSourceCols(p LogicalPlan, c *C, ans map[int][]string, comment CommentInterface) {
switch p.(type) {
case *DataSource:
colList, ok := ans[p.ID()]
c.Assert(ok, IsTrue, comment)
for i, colName := range colList {
c.Assert(colName, Equals, p.Schema().Columns[i].ColName.L, comment)
}
}
for _, child := range p.Children() {
checkDataSourceCols(child, c, ans, comment)
}
}
func (s *testPlanSuite) TestValidate(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
err *terror.Error
}{
{
sql: "select date_format((1,2), '%H');",
err: expression.ErrOperandColumns,
},
{
sql: "select cast((1,2) as date)",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2) between (3,4) and (5,6)",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2) rlike '1'",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2) like '1'",
err: expression.ErrOperandColumns,
},
{
sql: "select case(1,2) when(1,2) then true end",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2) in ((3,4),(5,6))",
err: nil,
},
{
sql: "select row(1,(2,3)) in (select a,b from t)",
err: expression.ErrOperandColumns,
},
{
sql: "select row(1,2) in (select a,b from t)",
err: nil,
},
{
sql: "select (1,2) in ((3,4),5)",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2) is true",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2) is null",
err: expression.ErrOperandColumns,
},
{
sql: "select (+(1,2))=(1,2)",
err: nil,
},
{
sql: "select (-(1,2))=(1,2)",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2)||(1,2)",
err: expression.ErrOperandColumns,
},
{
sql: "select (1,2) < (3,4)",
err: nil,
},
{
sql: "select (1,2) < 3",
err: expression.ErrOperandColumns,
},
{
sql: "select 1, * from t",
err: ErrInvalidWildCard,
},
{
sql: "select *, 1 from t",
err: nil,
},
{
sql: "select 1, t.* from t",
err: nil,
},
{
sql: "select 1 from t t1, t t2 where t1.a > all((select a) union (select a))",
err: ErrAmbiguous,
},
{
sql: "insert into t set a = 1, b = a + 1",
err: nil,
},
{
sql: "insert into t set a = 1, b = values(a) + 1",
err: nil,
},
{
sql: "select a, b, c from t order by 0",
err: ErrUnknownColumn,
},
{
sql: "select a, b, c from t order by 4",
err: ErrUnknownColumn,
},
{
sql: "select a as c1, b as c1 from t order by c1",
err: ErrAmbiguous,
},
{
sql: "(select a as b, b from t) union (select a, b from t) order by b",
err: ErrAmbiguous,
},
{
sql: "(select a as b, b from t) union (select a, b from t) order by a",
err: ErrUnknownColumn,
},
{
sql: "select * from t t1 use index(e)",
err: ErrKeyDoesNotExist,
},
{
sql: "select a from t having c2",
err: ErrUnknownColumn,
},
{
sql: "select a from t group by c2 + 1 having c2",
err: ErrUnknownColumn,
},
{
sql: "select a as b, b from t having b",
err: ErrAmbiguous,
},
{
sql: "select a + 1 from t having a",
err: ErrUnknownColumn,
},
{
sql: "select a from t having sum(avg(a))",
err: ErrInvalidGroupFuncUse,
},
{
sql: "select concat(c_str, d_str) from t group by `concat(c_str, d_str)`",
err: nil,
},
{
sql: "select concat(c_str, d_str) from t group by `concat(c_str,d_str)`",
err: ErrUnknownColumn,
},
}
for _, tt := range tests {
sql := tt.sql
comment := Commentf("for %s", sql)
stmt, err := s.ParseOneStmt(sql, "", "")
c.Assert(err, IsNil, comment)
Preprocess(s.ctx, stmt, s.is, false)
_, err = BuildLogicalPlan(s.ctx, stmt, s.is)
if tt.err == nil {
c.Assert(err, IsNil, comment)
} else {
c.Assert(tt.err.Equal(err), IsTrue, comment)
}
}
}
func checkUniqueKeys(p LogicalPlan, c *C, ans map[int][][]string, sql string) {
keyList, ok := ans[p.ID()]
c.Assert(ok, IsTrue, Commentf("for %s, %v not found", sql, p.ID()))
c.Assert(len(p.Schema().Keys), Equals, len(keyList), Commentf("for %s, %v, the number of key doesn't match, the schema is %s", sql, p.ID(), p.Schema()))
for i, key := range keyList {
c.Assert(len(key), Equals, len(p.Schema().Keys[i]), Commentf("for %s, %v %v, the number of column doesn't match", sql, p.ID(), key))
for j, colName := range key {
c.Assert(colName, Equals, p.Schema().Keys[i][j].String(), Commentf("for %s, %v %v, column dosen't match", sql, p.ID(), key))
}
}
for _, child := range p.Children() {
checkUniqueKeys(child, c, ans, sql)
}
}
func (s *testPlanSuite) TestUniqueKeyInfo(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
ans map[int][][]string
}{
{
sql: "select a, sum(e) from t group by b",
ans: map[int][][]string{
1: {{"test.t.a"}},
2: {{"test.t.a"}},
3: {{"test.t.a"}},
},
},
{
sql: "select a, b, sum(f) from t group by b",
ans: map[int][][]string{
1: {{"test.t.f"}, {"test.t.a"}},
2: {{"test.t.a"}, {"test.t.b"}},
3: {{"test.t.a"}, {"test.t.b"}},
},
},
{
sql: "select c, d, e, sum(a) from t group by c, d, e",
ans: map[int][][]string{
1: {{"test.t.a"}},
2: {{"test.t.c", "test.t.d", "test.t.e"}},
3: {{"test.t.c", "test.t.d", "test.t.e"}},
},
},
{
sql: "select f, g, sum(a) from t",
ans: map[int][][]string{
1: {{"test.t.f"}, {"test.t.f", "test.t.g"}, {"test.t.a"}},
2: {{"test.t.f"}, {"test.t.f", "test.t.g"}},
3: {{"test.t.f"}, {"test.t.f", "test.t.g"}},
},
},
{
sql: "select * from t t1 join t t2 on t1.a = t2.e",
ans: map[int][][]string{
1: {{"t1.f"}, {"t1.f", "t1.g"}, {"t1.a"}},
2: {{"t2.f"}, {"t2.f", "t2.g"}, {"t2.a"}},
3: {{"t2.f"}, {"t2.f", "t2.g"}, {"t2.a"}},
4: {{"t2.f"}, {"t2.f", "t2.g"}, {"t2.a"}},
},
},
{
sql: "select f from t having sum(a) > 0",
ans: map[int][][]string{
1: {{"test.t.f"}, {"test.t.a"}},
2: {{"test.t.f"}},
6: {{"test.t.f"}},
3: {{"test.t.f"}},
5: {{"test.t.f"}},
},
},
{
sql: "select * from t t1 left join t t2 on t1.a = t2.a",
ans: map[int][][]string{
1: {{"t1.f"}, {"t1.f", "t1.g"}, {"t1.a"}},
2: {{"t2.f"}, {"t2.f", "t2.g"}, {"t2.a"}},
3: {{"t1.f"}, {"t1.f", "t1.g"}, {"t1.a"}},
4: {{"t1.f"}, {"t1.f", "t1.g"}, {"t1.a"}},
},
},
}
for _, tt := range tests {
comment := Commentf("for %s", tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
lp, err := logicalOptimize(flagPredicatePushDown|flagPrunColumns|flagBuildKeyInfo, p.(LogicalPlan))
c.Assert(err, IsNil)
checkUniqueKeys(lp, c, tt.ans, tt.sql)
}
}
func (s *testPlanSuite) TestAggPrune(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
best string
}{
{
sql: "select a, count(b) from t group by a",
best: "DataScan(t)->Projection->Projection",
},
{
sql: "select sum(b) from t group by c, d, e",
best: "DataScan(t)->Aggr(sum(test.t.b))->Projection",
},
{
sql: "select tt.a, sum(tt.b) from (select a, b from t) tt group by tt.a",
best: "DataScan(t)->Projection->Projection",
},
{
sql: "select count(1) from (select count(1), a as b from t group by a) tt group by b",
best: "DataScan(t)->Projection->Projection",
},
}
for _, tt := range tests {
comment := Commentf("for %s", tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := BuildLogicalPlan(s.ctx, stmt, s.is)
c.Assert(err, IsNil)
p, err = logicalOptimize(flagPredicatePushDown|flagPrunColumns|flagBuildKeyInfo|flagEliminateAgg|flagEliminateProjection, p.(LogicalPlan))
c.Assert(err, IsNil)
c.Assert(ToString(p), Equals, tt.best, comment)
}
}
func (s *testPlanSuite) TestVisitInfo(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
ans []visitInfo
}{
{
sql: "insert into t (a) values (1)",
ans: []visitInfo{
{mysql.InsertPriv, "test", "t", ""},
},
},
{
sql: "delete from t where a = 1",
ans: []visitInfo{
{mysql.DeletePriv, "test", "t", ""},
{mysql.SelectPriv, "test", "t", ""},
},
},
{
sql: "delete from a1 using t as a1 inner join t as a2 where a1.a = a2.a",
ans: []visitInfo{
{mysql.DeletePriv, "test", "t", ""},
{mysql.SelectPriv, "test", "t", ""},
},
},
{
sql: "update t set a = 7 where a = 1",
ans: []visitInfo{
{mysql.UpdatePriv, "test", "t", ""},
{mysql.SelectPriv, "test", "t", ""},
},
},
{
sql: "update t, (select * from t) a1 set t.a = a1.a;",
ans: []visitInfo{
{mysql.UpdatePriv, "test", "t", ""},
{mysql.SelectPriv, "test", "t", ""},
},
},
{
sql: "select a, sum(e) from t group by a",
ans: []visitInfo{
{mysql.SelectPriv, "test", "t", ""},
},
},
{
sql: "truncate table t",
ans: []visitInfo{
{mysql.DeletePriv, "test", "t", ""},
},
},
{
sql: "drop table t",
ans: []visitInfo{
{mysql.DropPriv, "test", "t", ""},
},
},
{
sql: "create table t (a int)",
ans: []visitInfo{
{mysql.CreatePriv, "test", "t", ""},
},
},
{
sql: "create table t1 like t",
ans: []visitInfo{
{mysql.CreatePriv, "test", "t1", ""},
{mysql.SelectPriv, "test", "t", ""},
},
},
{
sql: "create database test",
ans: []visitInfo{
{mysql.CreatePriv, "test", "", ""},
},
},
{
sql: "drop database test",
ans: []visitInfo{
{mysql.DropPriv, "test", "", ""},
},
},
{
sql: "create index t_1 on t (a)",
ans: []visitInfo{
{mysql.IndexPriv, "test", "t", ""},
},
},
{
sql: "drop index e on t",
ans: []visitInfo{
{mysql.IndexPriv, "test", "t", ""},
},
},
{
sql: `create user 'test'@'%' identified by '123456'`,
ans: []visitInfo{
{mysql.CreateUserPriv, "", "", ""},
},
},
{
sql: `drop user 'test'@'%'`,
ans: []visitInfo{
{mysql.CreateUserPriv, "", "", ""},
},
},
{
sql: `grant all privileges on test.* to 'test'@'%'`,
ans: []visitInfo{
{mysql.SelectPriv, "test", "", ""},
{mysql.InsertPriv, "test", "", ""},
{mysql.UpdatePriv, "test", "", ""},
{mysql.DeletePriv, "test", "", ""},
{mysql.CreatePriv, "test", "", ""},
{mysql.DropPriv, "test", "", ""},
{mysql.GrantPriv, "test", "", ""},
{mysql.AlterPriv, "test", "", ""},
{mysql.ExecutePriv, "test", "", ""},
{mysql.IndexPriv, "test", "", ""},
},
},
{
sql: `grant select on test.ttt to 'test'@'%'`,
ans: []visitInfo{
{mysql.SelectPriv, "test", "ttt", ""},
{mysql.GrantPriv, "test", "ttt", ""},
},
},
{
sql: `revoke all privileges on *.* from 'test'@'%'`,
ans: []visitInfo{
{mysql.SuperPriv, "", "", ""},
},
},
{
sql: `set password for 'root'@'%' = 'xxxxx'`,
ans: []visitInfo{
{mysql.SuperPriv, "", "", ""},
},
},
{
sql: `show create table test.ttt`,
ans: []visitInfo{
{mysql.AllPrivMask, "test", "ttt", ""},
},
},
}
for _, tt := range tests {
comment := Commentf("for %s", tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
Preprocess(s.ctx, stmt, s.is, false)
builder := &PlanBuilder{
colMapper: make(map[*ast.ColumnNameExpr]int),
ctx: mockContext(),
is: s.is,
}
builder.ctx.GetSessionVars().HashJoinConcurrency = 1
_, err = builder.Build(stmt)
c.Assert(err, IsNil, comment)
checkVisitInfo(c, builder.visitInfo, tt.ans, comment)
}
}
type visitInfoArray []visitInfo
func (v visitInfoArray) Len() int {
return len(v)
}
func (v visitInfoArray) Less(i, j int) bool {
if v[i].privilege < v[j].privilege {
return true
}
if v[i].db < v[j].db {
return true
}
if v[i].table < v[j].table {
return true
}
if v[i].column < v[j].column {
return true
}
return false
}
func (v visitInfoArray) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func unique(v []visitInfo) []visitInfo {
repeat := 0
for i := 1; i < len(v); i++ {
if v[i] == v[i-1] {
repeat++
} else {
v[i-repeat] = v[i]
}
}
return v[:len(v)-repeat]
}
func checkVisitInfo(c *C, v1, v2 []visitInfo, comment CommentInterface) {
sort.Sort(visitInfoArray(v1))
sort.Sort(visitInfoArray(v2))
v1 = unique(v1)
v2 = unique(v2)
c.Assert(len(v1), Equals, len(v2), comment)
for i := 0; i < len(v1); i++ {
c.Assert(v1[i], Equals, v2[i], comment)
}
}
func (s *testPlanSuite) TestUnion(c *C) {
defer func() {
testleak.AfterTest(c)()
}()
tests := []struct {
sql string
best string
err bool
}{
{
sql: "select a from t union select a from t",
best: "UnionAll{DataScan(t)->Projection->DataScan(t)->Projection}->Aggr(firstrow(t.a))",
err: false,
},
{
sql: "select a from t union all select a from t",
best: "UnionAll{DataScan(t)->Projection->DataScan(t)->Projection}",
err: false,
},
{
sql: "select a from t union select a from t union all select a from t",
best: "UnionAll{DataScan(t)->Projection->UnionAll{DataScan(t)->Projection->DataScan(t)->Projection}->Aggr(firstrow(t.a))->Projection}",
err: false,
},
{
sql: "select a from t union select a from t union all select a from t union select a from t union select a from t",
best: "UnionAll{DataScan(t)->Projection->DataScan(t)->Projection->DataScan(t)->Projection->DataScan(t)->Projection->DataScan(t)->Projection}->Aggr(firstrow(t.a))",
err: false,
},
{
sql: "select a from t union select a, b from t",
best: "",
err: true,
},
}
for i, tt := range tests {
comment := Commentf("case:%v sql:%s", i, tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
Preprocess(s.ctx, stmt, s.is, false)
builder := &PlanBuilder{
ctx: mockContext(),
is: s.is,
colMapper: make(map[*ast.ColumnNameExpr]int),
}
plan, err := builder.Build(stmt)
if tt.err {
c.Assert(err, NotNil)
return
}
c.Assert(err, IsNil)
p := plan.(LogicalPlan)
p, err = logicalOptimize(builder.optFlag, p.(LogicalPlan))
c.Assert(err, IsNil)
c.Assert(ToString(p), Equals, tt.best, comment)
}
}
func (s *testPlanSuite) TestTopNPushDown(c *C) {
defer func() {
testleak.AfterTest(c)()
}()
tests := []struct {
sql string
best string
}{
// Test TopN + Selection.
{
sql: "select * from t where a < 1 order by b limit 5",
best: "DataScan(t)->TopN([test.t.b],0,5)->Projection",
},
// Test Limit + Selection.
{
sql: "select * from t where a < 1 limit 5",
best: "DataScan(t)->Limit->Projection",
},
// Test Limit + Agg + Proj .
{
sql: "select a, count(b) from t group by b limit 5",
best: "DataScan(t)->Aggr(count(test.t.b),firstrow(test.t.a))->Limit->Projection",
},
// Test TopN + Agg + Proj .
{
sql: "select a, count(b) from t group by b order by c limit 5",
best: "DataScan(t)->Aggr(count(test.t.b),firstrow(test.t.a),firstrow(test.t.c))->TopN([test.t.c],0,5)->Projection",
},
// Test TopN + Join + Proj.
{
sql: "select * from t, t s order by t.a limit 5",
best: "Join{DataScan(t)->DataScan(s)}->TopN([test.t.a],0,5)->Projection",
},
// Test Limit + Join + Proj.
{
sql: "select * from t, t s limit 5",
best: "Join{DataScan(t)->DataScan(s)}->Limit->Projection",
},
// Test TopN + Left Join + Proj.
{
sql: "select * from t left outer join t s on t.a = s.a order by t.a limit 5",
best: "Join{DataScan(t)->TopN([test.t.a],0,5)->DataScan(s)}(test.t.a,s.a)->TopN([test.t.a],0,5)->Projection",
},
// Test TopN + Left Join + Proj.
{
sql: "select * from t left outer join t s on t.a = s.a order by t.a limit 5, 5",
best: "Join{DataScan(t)->TopN([test.t.a],0,10)->DataScan(s)}(test.t.a,s.a)->TopN([test.t.a],5,5)->Projection",
},
// Test Limit + Left Join + Proj.
{
sql: "select * from t left outer join t s on t.a = s.a limit 5",
best: "Join{DataScan(t)->Limit->DataScan(s)}(test.t.a,s.a)->Limit->Projection",
},
// Test Limit + Left Join Apply + Proj.
{
sql: "select (select s.a from t s where t.a = s.a) from t limit 5",
best: "Join{DataScan(t)->Limit->DataScan(s)}(test.t.a,s.a)->Limit->Projection",
},
// Test TopN + Left Join Apply + Proj.
{
sql: "select (select s.a from t s where t.a = s.a) from t order by t.a limit 5",
best: "Join{DataScan(t)->TopN([test.t.a],0,5)->DataScan(s)}(test.t.a,s.a)->TopN([test.t.a],0,5)->Projection",
},
// Test TopN + Left Semi Join Apply + Proj.
{
sql: "select exists (select s.a from t s where t.a = s.a) from t order by t.a limit 5",
best: "Join{DataScan(t)->TopN([test.t.a],0,5)->DataScan(s)}(test.t.a,s.a)->TopN([test.t.a],0,5)->Projection",
},
// Test TopN + Semi Join Apply + Proj.
{
sql: "select * from t where exists (select s.a from t s where t.a = s.a) order by t.a limit 5",
best: "Join{DataScan(t)->DataScan(s)}(test.t.a,s.a)->TopN([test.t.a],0,5)->Projection",
},
// Test TopN + Right Join + Proj.
{
sql: "select * from t right outer join t s on t.a = s.a order by s.a limit 5",
best: "Join{DataScan(t)->DataScan(s)->TopN([s.a],0,5)}(test.t.a,s.a)->TopN([s.a],0,5)->Projection",
},
// Test Limit + Right Join + Proj.
{
sql: "select * from t right outer join t s on t.a = s.a order by s.a,t.b limit 5",
best: "Join{DataScan(t)->DataScan(s)}(test.t.a,s.a)->TopN([s.a test.t.b],0,5)->Projection",
},
// Test TopN + UA + Proj.
{
sql: "select * from t union all (select * from t s) order by a,b limit 5",
best: "UnionAll{DataScan(t)->TopN([test.t.a test.t.b],0,5)->Projection->DataScan(s)->TopN([s.a s.b],0,5)->Projection}->TopN([t.a t.b],0,5)",
},
// Test TopN + UA + Proj.
{
sql: "select * from t union all (select * from t s) order by a,b limit 5, 5",
best: "UnionAll{DataScan(t)->TopN([test.t.a test.t.b],0,10)->Projection->DataScan(s)->TopN([s.a s.b],0,10)->Projection}->TopN([t.a t.b],5,5)",
},
// Test Limit + UA + Proj + Sort.
{
sql: "select * from t union all (select * from t s order by a) limit 5",
best: "UnionAll{DataScan(t)->Limit->Projection->DataScan(s)->TopN([s.a],0,5)->Projection}->Limit",
},
// Test `ByItem` containing column from both sides.
{
sql: "select ifnull(t1.b, t2.a) from t t1 left join t t2 on t1.e=t2.e order by ifnull(t1.b, t2.a) limit 5",
best: "Join{DataScan(t1)->DataScan(t2)}(t1.e,t2.e)->TopN([ifnull(t1.b, t2.a)],0,5)->Projection->Projection",
},
}
for i, tt := range tests {
comment := Commentf("case:%v sql:%s", i, tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
Preprocess(s.ctx, stmt, s.is, false)
builder := &PlanBuilder{
ctx: mockContext(),
is: s.is,
colMapper: make(map[*ast.ColumnNameExpr]int),
}
p, err := builder.Build(stmt)
c.Assert(err, IsNil)
p, err = logicalOptimize(builder.optFlag, p.(LogicalPlan))
c.Assert(err, IsNil)
c.Assert(ToString(p), Equals, tt.best, comment)
}
}
func (s *testPlanSuite) TestNameResolver(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
sql string
err string
}{
{"select a from t", ""},
{"select c3 from t", "[planner:1054]Unknown column 'c3' in 'field list'"},
{"select c1 from t4", "[schema:1146]Table 'test.t4' doesn't exist"},
{"select * from t", ""},
{"select t.* from t", ""},
{"select t2.* from t", "[planner:1051]Unknown table 't2'"},
{"select b as a, c as a from t group by a", "[planner:1052]Column 'c' in field list is ambiguous"},
{"select 1 as a, b as a, c as a from t group by a", ""},
{"select a, b as a from t group by a+1", ""},
{"select c, a as c from t order by c+1", ""},
{"select * from t as t1, t as t2 join t as t3 on t2.a = t3.a", ""},
{"select * from t as t1, t as t2 join t as t3 on t1.c1 = t2.a", "[planner:1054]Unknown column 't1.c1' in 'on clause'"},
{"select a from t group by a having a = 3", ""},
{"select a from t group by a having c2 = 3", "[planner:1054]Unknown column 'c2' in 'having clause'"},
{"select a from t where exists (select b)", ""},
{"select cnt from (select count(a) as cnt from t group by b) as t2 group by cnt", ""},
{"select a from t where t11.a < t.a", "[planner:1054]Unknown column 't11.a' in 'where clause'"},
{"select a from t having t11.c1 < t.a", "[planner:1054]Unknown column 't11.c1' in 'having clause'"},
{"select a from t where t.a < t.a order by t11.c1", "[planner:1054]Unknown column 't11.c1' in 'order clause'"},
{"select a from t group by t11.c1", "[planner:1054]Unknown column 't11.c1' in 'group statement'"},
{"delete a from (select * from t ) as a, t", "[planner:1288]The target table a of the DELETE is not updatable"},
{"delete b from (select * from t ) as a, t", "[planner:1109]Unknown table 'b' in MULTI DELETE"},
{"select '' as fakeCol from t group by values(fakeCol)", "[planner:1054]Unknown column '' in 'VALUES() function'"},
{"update t, (select * from t) as b set b.a = t.a", "[planner:1288]The target table b of the UPDATE is not updatable"},
}
for _, t := range tests {
comment := Commentf("for %s", t.sql)
stmt, err := s.ParseOneStmt(t.sql, "", "")
c.Assert(err, IsNil, comment)
s.ctx.GetSessionVars().HashJoinConcurrency = 1
_, err = BuildLogicalPlan(s.ctx, stmt, s.is)
if t.err == "" {
c.Check(err, IsNil)
} else {
c.Assert(err.Error(), Equals, t.err)
}
}
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/hanchuanchuan-goInception.git
git@gitlife.ru:oschina-mirror/hanchuanchuan-goInception.git
oschina-mirror
hanchuanchuan-goInception
hanchuanchuan-goInception
v1.3.0