From d92ea8babf7724ef91393cc373a53a2148a55caa Mon Sep 17 00:00:00 2001 From: Pat Okeeffe <85502298+paddyjok@users.noreply.github.com> Date: Wed, 25 Jan 2023 13:37:05 -0600 Subject: [PATCH] hand comma version of inner join (#2221) --- sql3/parser/ast.go | 22 +++++++++++++++------- sql3/planner/compileselect.go | 14 +++++++++++++- sql3/planner/opnestedloops.go | 9 +++++---- sql3/planner/planoptimizer.go | 1 + sql3/test/defs/defs.go | 4 ++-- sql3/test/defs/defs_join.go | 18 ++++++++++++++++++ sql3/test/defs/defs_timequantum.go | 1 - 7 files changed, 54 insertions(+), 15 deletions(-) diff --git a/sql3/parser/ast.go b/sql3/parser/ast.go index b508e918f..80bedc372 100644 --- a/sql3/parser/ast.go +++ b/sql3/parser/ast.go @@ -3802,7 +3802,12 @@ func (c *ParenSource) SourceFromAlias(alias string) Source { } func (c *ParenSource) PossibleOutputColumns() []*SourceOutputColumn { - return c.X.PossibleOutputColumns() + aliasName := IdentName(c.Alias) + poc := c.X.PossibleOutputColumns() + for _, pc := range poc { + pc.TableName = aliasName + } + return poc } func (c *ParenSource) OutputColumnNamed(name string) (*SourceOutputColumn, error) { @@ -3817,11 +3822,10 @@ func (c *ParenSource) OutputColumnQualifierNamed(qualifier string, name string) } type JoinClause struct { - X Source // lhs source - Operator *JoinOperator // join operator - Y Source // rhs source - Constraint JoinConstraint // join constraint - OutputColumns []*SourceOutputColumn // output columns - populated during analysis + X Source // lhs source + Operator *JoinOperator // join operator + Y Source // rhs source + Constraint JoinConstraint // join constraint } // Clone returns a deep copy of c. @@ -3847,7 +3851,11 @@ func (c *JoinClause) String() string { } func (c *JoinClause) PossibleOutputColumns() []*SourceOutputColumn { - return c.OutputColumns + poc := make([]*SourceOutputColumn, 0) + poc = append(poc, c.X.PossibleOutputColumns()...) + poc = append(poc, c.Y.PossibleOutputColumns()...) + return poc + } func (c *JoinClause) OutputColumnNamed(name string) (*SourceOutputColumn, error) { diff --git a/sql3/planner/compileselect.go b/sql3/planner/compileselect.go index 5682d24b1..f42011482 100644 --- a/sql3/planner/compileselect.go +++ b/sql3/planner/compileselect.go @@ -643,12 +643,24 @@ func (p *ExecutionPlanner) analyzeSelectStatementWildcards(stmt *parser.SelectSt return nil } +// TODO(pok) - looks increasingly likely that this can be factored out since all join types +// do the same thing func (p *ExecutionPlanner) columnsFromSource(source parser.Source) ([]*parser.ResultColumn, error) { result := []*parser.ResultColumn{} switch src := source.(type) { case *parser.JoinClause: - return nil, sql3.NewErrInternal("joins are not currently supported") + for _, oc := range src.PossibleOutputColumns() { + result = append(result, &parser.ResultColumn{ + Expr: &parser.QualifiedRef{ + Table: &parser.Ident{Name: oc.TableName}, + Column: &parser.Ident{Name: oc.ColumnName}, + ColumnIndex: oc.ColumnIndex, + }, + }) + } + return result, nil + case *parser.ParenSource: for _, oc := range src.PossibleOutputColumns() { result = append(result, &parser.ResultColumn{ diff --git a/sql3/planner/opnestedloops.go b/sql3/planner/opnestedloops.go index d4116baa5..34d8c9789 100644 --- a/sql3/planner/opnestedloops.go +++ b/sql3/planner/opnestedloops.go @@ -36,7 +36,9 @@ func (p *PlanOpNestedLoops) Plan() map[string]interface{} { result["_schema"] = p.Schema().Plan() result["top"] = p.top.Plan() result["bottom"] = p.bottom.Plan() - result["condition"] = p.cond.Plan() + if p.cond != nil { + result["condition"] = p.cond.Plan() + } return result } @@ -93,10 +95,9 @@ func (p *PlanOpNestedLoops) Expressions() []types.PlanExpression { } func (p *PlanOpNestedLoops) WithUpdatedExpressions(exprs ...types.PlanExpression) (types.PlanOperator, error) { - if len(exprs) != 1 { - return nil, sql3.NewErrInternalf("unexpected number of exprs '%d'", len(exprs)) + if len(exprs) == 1 { + p.cond = exprs[0] } - p.cond = exprs[0] return p, nil } diff --git a/sql3/planner/planoptimizer.go b/sql3/planner/planoptimizer.go index 72298c90c..b3adaf73a 100644 --- a/sql3/planner/planoptimizer.go +++ b/sql3/planner/planoptimizer.go @@ -13,6 +13,7 @@ import ( "github.com/featurebasedb/featurebase/v3/sql3/planner/types" ) +//TODO(pok) push filter down into join condition if terms reference either side of join //TODO(pok) push order by down as far as possible //TODO(pok) handle the case of the order by expressions not being in a projection list //TODO(pok) you can't group by _id in PQL, so we need to not use a PQL group by operator here diff --git a/sql3/test/defs/defs.go b/sql3/test/defs/defs.go index 42dcd6494..41619d43c 100644 --- a/sql3/test/defs/defs.go +++ b/sql3/test/defs/defs.go @@ -170,8 +170,8 @@ var TableTests []TableTest = []TableTest{ //bool (batch logic) boolTests, - //time quantums - // Skip for now - timeQuantumInsertTest, + // time quantums + timeQuantumInsertTest, } func knownTimestamp() time.Time { diff --git a/sql3/test/defs/defs_join.go b/sql3/test/defs/defs_join.go index bd23e95de..4af218aee 100644 --- a/sql3/test/defs/defs_join.go +++ b/sql3/test/defs/defs_join.go @@ -137,6 +137,24 @@ var joinTests = TableTest{ ), ExpErr: "RIGHT join types are not supported", }, + { + name: "commajoin", + SQLs: sqls( + "select u._id, u.name, u.age, u2._id as u2_id, u2.name as u2name, u2.age as u2age from users u, (select * from users where _id=2) u2 where u._id=u2._id;", + ), + ExpHdrs: hdrs( + hdr("_id", fldTypeID), + hdr("name", fldTypeString), + hdr("age", fldTypeInt), + hdr("u2_id", fldTypeID), + hdr("u2name", fldTypeString), + hdr("u2age", fldTypeInt), + ), + ExpRows: rows( + row(int64(2), string("c"), int64(28), int64(2), string("c"), int64(28)), + ), + Compare: CompareExactUnordered, + }, }, PQLTests: []PQLTest{ { diff --git a/sql3/test/defs/defs_timequantum.go b/sql3/test/defs/defs_timequantum.go index 94ad34b52..5aa898e05 100644 --- a/sql3/test/defs/defs_timequantum.go +++ b/sql3/test/defs/defs_timequantum.go @@ -9,7 +9,6 @@ var timeQuantumInsertTest = TableTest{ srcHdr("i1", fldTypeInt, "min 0", "max 1000"), srcHdr("ids1", fldTypeIDSet, "timequantum 'YMD'"), ), - srcRows(), ), SQLTests: []SQLTest{ {