Skip to content

Commit 2bdb5d3

Browse files
committed
Table as column draft
1 parent 83d2fda commit 2bdb5d3

File tree

7 files changed

+234
-18
lines changed

7 files changed

+234
-18
lines changed

enginetest/memory_engine_test.go

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -200,23 +200,30 @@ func TestSingleQueryPrepared(t *testing.T) {
200200

201201
// Convenience test for debugging a single query. Unskip and set to the desired query.
202202
func TestSingleScript(t *testing.T) {
203-
t.Skip()
203+
//t.Skip()
204204
var scripts = []queries.ScriptTest{
205205
{
206-
Name: "AS OF propagates to nested CALLs",
207-
SetUpScript: []string{},
206+
Name: "AS OF propagates to nested CALLs",
207+
SetUpScript: []string{
208+
`CREATE TABLE test (pk INT PRIMARY KEY, v1 VARCHAR(255));`,
209+
`INSERT INTO test VALUES (1, 'a'), (2, 'b');`,
210+
},
208211
Assertions: []queries.ScriptTestAssertion{
209212
{
210-
Query: "create procedure create_proc() create table t (i int primary key, j int);",
211-
Expected: []sql.Row{
212-
{types.NewOkResult(0)},
213-
},
213+
Query: "SELECT temporarytesting(t) FROM test AS t;",
214+
Expected: []sql.Row{},
214215
},
215216
{
216-
Query: "call create_proc()",
217-
Expected: []sql.Row{
218-
{types.NewOkResult(0)},
219-
},
217+
Query: "SELECT temporarytesting(test) FROM test;",
218+
Expected: []sql.Row{},
219+
},
220+
{
221+
Query: "SELECT temporarytesting(pk, test) FROM test;",
222+
Expected: []sql.Row{},
223+
},
224+
{
225+
Query: "SELECT temporarytesting(v1, test, pk) FROM test;",
226+
Expected: []sql.Row{},
220227
},
221228
},
222229
},

sql/expression/alias.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,52 @@ func (e *Alias) WithChildren(children ...sql.Expression) (sql.Expression, error)
165165

166166
// Name implements the Nameable interface.
167167
func (e *Alias) Name() string { return e.name }
168+
169+
// TODO: DELETE EVERYTHING UNDER HERE -----------------------------------------------------------------------
170+
// ---------------------------------------------------------------------------------------------------------
171+
// ---------------------------------------------------------------------------------------------------------
172+
// ---------------------------------------------------------------------------------------------------------
173+
// ---------------------------------------------------------------------------------------------------------
174+
175+
// This is an expression that will be returned from a Doltgres hook (GMS' hook will return a nil expression to indicate
176+
// incompatibility). This function is just a stand-in for testing purposes.
177+
type DoltgresHookExpression struct {
178+
args []sql.Expression
179+
}
180+
181+
var _ sql.Expression = (*DoltgresHookExpression)(nil)
182+
183+
func NewDoltgresHookExpression(args ...sql.Expression) sql.Expression {
184+
return &DoltgresHookExpression{args: args}
185+
}
186+
187+
func (tt *DoltgresHookExpression) String() string { return "temporarytesting2" }
188+
189+
// Type implements the Expression interface.
190+
func (tt *DoltgresHookExpression) Type() sql.Type { return types.Int32 }
191+
192+
// Eval implements the Expression interface.
193+
func (tt *DoltgresHookExpression) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
194+
rowLen := len(row)
195+
return int32(-rowLen), nil
196+
}
197+
198+
// Resolved implements the Expression interface.
199+
func (tt *DoltgresHookExpression) Resolved() bool {
200+
return true
201+
}
202+
203+
// Children implements the Expression interface.
204+
func (tt *DoltgresHookExpression) Children() []sql.Expression {
205+
return tt.args
206+
}
207+
208+
// IsNullable implements the Expression interface.
209+
func (tt *DoltgresHookExpression) IsNullable() bool {
210+
return false
211+
}
212+
213+
// WithChildren implements the Expression interface.
214+
func (*DoltgresHookExpression) WithChildren(children ...sql.Expression) (sql.Expression, error) {
215+
return NewDoltgresHookExpression(children...), nil
216+
}

sql/expression/function/registry.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/dolthub/go-mysql-server/sql/expression/function/json"
2626
"github.com/dolthub/go-mysql-server/sql/expression/function/spatial"
2727
"github.com/dolthub/go-mysql-server/sql/expression/function/vector"
28+
"github.com/dolthub/go-mysql-server/sql/types"
2829
)
2930

3031
// ErrFunctionAlreadyRegistered is thrown when a function is already registered
@@ -342,6 +343,7 @@ var BuiltIns = []sql.Function{
342343
sql.Function1{Name: "weekofyear", Fn: NewWeekOfYear},
343344
sql.Function1{Name: "year", Fn: NewYear},
344345
sql.FunctionN{Name: "yearweek", Fn: NewYearWeek},
346+
sql.FunctionN{Name: "temporarytesting", Fn: NewTemporaryTesting}, // TODO: DELETE ME
345347
}
346348

347349
func GetLockingFuncs(ls *sql.LockSubsystem) []sql.Function {
@@ -390,3 +392,65 @@ func (r Registry) mustRegister(fn ...sql.Function) {
390392
panic(err)
391393
}
392394
}
395+
396+
// TODO: DELETE EVERYTHING UNDER HERE -----------------------------------------------------------------------
397+
// ---------------------------------------------------------------------------------------------------------
398+
// ---------------------------------------------------------------------------------------------------------
399+
// ---------------------------------------------------------------------------------------------------------
400+
// ---------------------------------------------------------------------------------------------------------
401+
402+
// This is an example Doltgres function. This exists solely for testing purposes, and will be deleted as noted by the
403+
// massive comment above this.
404+
type DoltgresFunction struct {
405+
args []sql.Expression
406+
}
407+
408+
var _ sql.FunctionExpression = (*DoltgresFunction)(nil)
409+
410+
func NewTemporaryTesting(args ...sql.Expression) (sql.Expression, error) {
411+
return &DoltgresFunction{args: args}, nil
412+
}
413+
414+
// FunctionName implements sql.FunctionExpression
415+
func (tt *DoltgresFunction) FunctionName() string {
416+
return "temporarytesting"
417+
}
418+
419+
// Description implements sql.FunctionExpression
420+
func (tt *DoltgresFunction) Description() string {
421+
return ""
422+
}
423+
424+
func (tt *DoltgresFunction) String() string { return "temporarytesting()" }
425+
426+
// Type implements the Expression interface.
427+
func (tt *DoltgresFunction) Type() sql.Type { return types.Int32 }
428+
429+
// CollationCoercibility implements the interface sql.CollationCoercible.
430+
func (*DoltgresFunction) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
431+
return sql.Collation_binary, 5
432+
}
433+
434+
// Eval implements the Expression interface.
435+
func (tt *DoltgresFunction) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
436+
rowLen := len(row)
437+
return int32(rowLen), nil
438+
}
439+
440+
// Resolved implements the Expression interface.
441+
func (tt *DoltgresFunction) Resolved() bool {
442+
return true
443+
}
444+
445+
// Children implements the Expression interface.
446+
func (tt *DoltgresFunction) Children() []sql.Expression { return tt.args }
447+
448+
// IsNullable implements the Expression interface.
449+
func (tt *DoltgresFunction) IsNullable() bool {
450+
return false
451+
}
452+
453+
// WithChildren implements the Expression interface.
454+
func (*DoltgresFunction) WithChildren(children ...sql.Expression) (sql.Expression, error) {
455+
return NewTemporaryTesting(children...)
456+
}

sql/functions.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ func NewFunction0(name string, fn func() Expression) Function0 {
108108
}
109109
}
110110

111+
// NewInstance implements the interface Function.
111112
func (fn Function0) NewInstance(args []Expression) (Expression, error) {
112113
if len(args) != 0 {
113114
return nil, ErrInvalidArgumentNumber.New(fn.Name, 0, len(args))
@@ -116,6 +117,7 @@ func (fn Function0) NewInstance(args []Expression) (Expression, error) {
116117
return fn.Fn(), nil
117118
}
118119

120+
// NewInstance implements the interface Function.
119121
func (fn Function1) NewInstance(args []Expression) (Expression, error) {
120122
if len(args) != 1 {
121123
return nil, ErrInvalidArgumentNumber.New(fn.Name, 1, len(args))
@@ -124,6 +126,7 @@ func (fn Function1) NewInstance(args []Expression) (Expression, error) {
124126
return fn.Fn(args[0]), nil
125127
}
126128

129+
// NewInstance implements the interface Function.
127130
func (fn Function2) NewInstance(args []Expression) (Expression, error) {
128131
if len(args) != 2 {
129132
return nil, ErrInvalidArgumentNumber.New(fn.Name, 2, len(args))
@@ -132,6 +135,7 @@ func (fn Function2) NewInstance(args []Expression) (Expression, error) {
132135
return fn.Fn(args[0], args[1]), nil
133136
}
134137

138+
// NewInstance implements the interface Function.
135139
func (fn Function3) NewInstance(args []Expression) (Expression, error) {
136140
if len(args) != 3 {
137141
return nil, ErrInvalidArgumentNumber.New(fn.Name, 3, len(args))
@@ -140,6 +144,7 @@ func (fn Function3) NewInstance(args []Expression) (Expression, error) {
140144
return fn.Fn(args[0], args[1], args[2]), nil
141145
}
142146

147+
// NewInstance implements the interface Function.
143148
func (fn Function4) NewInstance(args []Expression) (Expression, error) {
144149
if len(args) != 4 {
145150
return nil, ErrInvalidArgumentNumber.New(fn.Name, 4, len(args))
@@ -148,6 +153,7 @@ func (fn Function4) NewInstance(args []Expression) (Expression, error) {
148153
return fn.Fn(args[0], args[1], args[2], args[3]), nil
149154
}
150155

156+
// NewInstance implements the interface Function.
151157
func (fn Function5) NewInstance(args []Expression) (Expression, error) {
152158
if len(args) != 5 {
153159
return nil, ErrInvalidArgumentNumber.New(fn.Name, 5, len(args))
@@ -156,6 +162,7 @@ func (fn Function5) NewInstance(args []Expression) (Expression, error) {
156162
return fn.Fn(args[0], args[1], args[2], args[3], args[4]), nil
157163
}
158164

165+
// NewInstance implements the interface Function.
159166
func (fn Function6) NewInstance(args []Expression) (Expression, error) {
160167
if len(args) != 6 {
161168
return nil, ErrInvalidArgumentNumber.New(fn.Name, 6, len(args))
@@ -164,6 +171,7 @@ func (fn Function6) NewInstance(args []Expression) (Expression, error) {
164171
return fn.Fn(args[0], args[1], args[2], args[3], args[4], args[5]), nil
165172
}
166173

174+
// NewInstance implements the interface Function.
167175
func (fn Function7) NewInstance(args []Expression) (Expression, error) {
168176
if len(args) != 7 {
169177
return nil, ErrInvalidArgumentNumber.New(fn.Name, 7, len(args))
@@ -172,6 +180,7 @@ func (fn Function7) NewInstance(args []Expression) (Expression, error) {
172180
return fn.Fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]), nil
173181
}
174182

183+
// NewInstance implements the interface Function.
175184
func (fn FunctionN) NewInstance(args []Expression) (Expression, error) {
176185
return fn.Fn(args...)
177186
}

sql/planbuilder/from.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ func (b *Builder) buildResolvedTable(inScope *scope, db, schema, name string, as
751751
})
752752
cols.Add(sql.ColumnId(id))
753753
}
754+
outScope.recordTableAsColumn(db, strings.ToLower(tab.Name()), tabId, rt)
754755

755756
rt = rt.WithId(tabId).WithColumns(cols).(*plan.ResolvedTable)
756757
outScope.node = rt

sql/planbuilder/scalar.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,19 +136,44 @@ func (b *Builder) buildScalar(inScope *scope, e ast.Expr) (ex sql.Expression) {
136136
return sysVar
137137
}
138138
}
139-
var err error
140139
if scope == ast.SetScope_User || scope == ast.SetScope_Persist || scope == ast.SetScope_PersistOnly {
141-
err = sql.ErrUnknownUserVariable.New(colName)
140+
err := sql.ErrUnknownUserVariable.New(colName)
141+
b.handleErr(err)
142142
} else if scope == ast.SetScope_Global || scope == ast.SetScope_Session {
143-
err = sql.ErrUnknownSystemVariable.New(colName)
143+
err := sql.ErrUnknownSystemVariable.New(colName)
144+
b.handleErr(err)
144145
} else if tblName != "" && !inScope.hasTable(tblName) {
145-
err = sql.ErrTableNotFound.New(tblName)
146+
err := sql.ErrTableNotFound.New(tblName)
147+
b.handleErr(err)
146148
} else if tblName != "" {
147-
err = sql.ErrTableColumnNotFound.New(tblName, colName)
149+
err := sql.ErrTableColumnNotFound.New(tblName, colName)
150+
b.handleErr(err)
151+
} else if inScope.hasTable(colName) {
152+
// TODO: only relevant for Doltgres, this will use a hook
153+
scopeTable, ok := inScope.resolveColumnAsTable(dbName, colName)
154+
if !ok {
155+
err := sql.ErrColumnNotFound.New(v)
156+
b.handleErr(err)
157+
}
158+
tableSch := scopeTable.rt.Schema()
159+
astQualifier := ast.TableName{
160+
Name: ast.NewTableIdent(colName), // This must be the colName due to aliases
161+
DbQualifier: ast.NewTableIdent(scopeTable.rt.Database().Name()),
162+
}
163+
fieldArgs := make([]sql.Expression, len(tableSch))
164+
for i := range tableSch {
165+
astArg := ast.ColName{
166+
StoredProcVal: nil,
167+
Qualifier: astQualifier,
168+
Name: ast.NewColIdent(tableSch[i].Name),
169+
}
170+
fieldArgs[i] = b.buildScalar(inScope, &astArg)
171+
}
172+
return expression.NewDoltgresHookExpression(fieldArgs...)
148173
} else {
149-
err = sql.ErrColumnNotFound.New(v)
174+
err := sql.ErrColumnNotFound.New(v)
175+
b.handleErr(err)
150176
}
151-
b.handleErr(err)
152177
}
153178

154179
origTbl := b.getOrigTblName(inScope.node, c.table)

0 commit comments

Comments
 (0)