github.com/dolthub/go-mysql-server@v0.18.0/sql/planbuilder/from.go (about)

     1  // Copyright 2023 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package planbuilder
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	ast "github.com/dolthub/vitess/go/vt/sqlparser"
    22  
    23  	"github.com/dolthub/go-mysql-server/sql"
    24  	"github.com/dolthub/go-mysql-server/sql/expression"
    25  	"github.com/dolthub/go-mysql-server/sql/mysql_db"
    26  	"github.com/dolthub/go-mysql-server/sql/plan"
    27  	"github.com/dolthub/go-mysql-server/sql/transform"
    28  	"github.com/dolthub/go-mysql-server/sql/types"
    29  )
    30  
    31  // TODO outScope will be populated with a source node and column sets
    32  func (b *Builder) buildFrom(inScope *scope, te ast.TableExprs) (outScope *scope) {
    33  	if len(te) == 0 {
    34  		outScope = inScope.push()
    35  		outScope.ast = te
    36  		outScope.node = plan.NewResolvedDualTable()
    37  		// new unreferenceable column to mirror empty table schema
    38  		outScope.addColumn(scopeColumn{table: "dual"})
    39  		return
    40  	}
    41  
    42  	if len(te) > 1 {
    43  		cj := &ast.JoinTableExpr{
    44  			LeftExpr:  te[0],
    45  			RightExpr: te[1],
    46  			Join:      ast.JoinStr,
    47  			Condition: ast.JoinCondition{On: ast.BoolVal(true)},
    48  		}
    49  		for _, t := range te[2:] {
    50  			cj = &ast.JoinTableExpr{
    51  				LeftExpr:  cj,
    52  				RightExpr: t,
    53  				Join:      ast.JoinStr,
    54  				Condition: ast.JoinCondition{On: ast.BoolVal(true)},
    55  			}
    56  		}
    57  		return b.buildJoin(inScope, cj)
    58  	}
    59  	return b.buildDataSource(inScope, te[0])
    60  }
    61  
    62  func (b *Builder) isLateral(te ast.TableExpr) bool {
    63  	switch t := te.(type) {
    64  	case *ast.JSONTableExpr:
    65  		return true
    66  	case *ast.AliasedTableExpr:
    67  		return t.Lateral
    68  	default:
    69  		return false
    70  	}
    71  }
    72  
    73  func (b *Builder) isUsingJoin(te *ast.JoinTableExpr) bool {
    74  	return te.Condition.Using != nil ||
    75  		strings.EqualFold(te.Join, ast.NaturalJoinStr) ||
    76  		strings.EqualFold(te.Join, ast.NaturalLeftJoinStr) ||
    77  		strings.EqualFold(te.Join, ast.NaturalRightJoinStr)
    78  }
    79  
    80  func (b *Builder) buildJoin(inScope *scope, te *ast.JoinTableExpr) (outScope *scope) {
    81  	//TODO build individual table expressions
    82  	// collect column  definitions
    83  	leftScope := b.buildDataSource(inScope, te.LeftExpr)
    84  
    85  	// TODO lateral join right will see left outputs
    86  	rightInScope := inScope
    87  	if b.isLateral(te.RightExpr) && te.Join != ast.RightJoinStr {
    88  		rightInScope = leftScope
    89  	}
    90  	rightScope := b.buildDataSource(rightInScope, te.RightExpr)
    91  
    92  	if b.isUsingJoin(te) {
    93  		return b.buildUsingJoin(inScope, leftScope, rightScope, te)
    94  	}
    95  
    96  	outScope = inScope.push()
    97  	outScope.appendColumnsFromScope(leftScope)
    98  	outScope.appendColumnsFromScope(rightScope)
    99  
   100  	// cross join
   101  	if (te.Condition.On == nil || te.Condition.On == ast.BoolVal(true)) && te.Condition.Using == nil {
   102  		if rast, ok := te.RightExpr.(*ast.AliasedTableExpr); ok && rast.Lateral {
   103  			var err error
   104  			outScope.node, err = b.f.buildJoin(leftScope.node, rightScope.node, plan.JoinTypeLateralCross, expression.NewLiteral(true, types.Boolean))
   105  			if err != nil {
   106  				b.handleErr(err)
   107  			}
   108  		} else if b.isLateral(te.RightExpr) {
   109  			outScope.node = plan.NewJoin(leftScope.node, rightScope.node, plan.JoinTypeLateralCross, nil)
   110  		} else {
   111  			outScope.node = plan.NewCrossJoin(leftScope.node, rightScope.node)
   112  		}
   113  		return
   114  	}
   115  
   116  	var filter sql.Expression
   117  	if te.Condition.On != nil {
   118  		filter = b.buildScalar(outScope, te.Condition.On)
   119  	}
   120  
   121  	var op plan.JoinType
   122  	switch strings.ToLower(te.Join) {
   123  	case ast.JoinStr:
   124  		if b.isLateral(te.RightExpr) {
   125  			op = plan.JoinTypeLateralInner
   126  		} else {
   127  			op = plan.JoinTypeInner
   128  		}
   129  	case ast.LeftJoinStr:
   130  		if b.isLateral(te.RightExpr) {
   131  			op = plan.JoinTypeLateralLeft
   132  		} else {
   133  			op = plan.JoinTypeLeftOuter
   134  		}
   135  	case ast.RightJoinStr:
   136  		if b.isLateral(te.RightExpr) {
   137  			op = plan.JoinTypeLateralRight
   138  		} else {
   139  			op = plan.JoinTypeRightOuter
   140  		}
   141  	case ast.FullOuterJoinStr:
   142  		op = plan.JoinTypeFullOuter
   143  	default:
   144  		b.handleErr(fmt.Errorf("unknown join type: %s", te.Join))
   145  	}
   146  	var err error
   147  	outScope.node, err = b.f.buildJoin(leftScope.node, rightScope.node, op, filter)
   148  	if err != nil {
   149  		b.handleErr(err)
   150  	}
   151  
   152  	return outScope
   153  }
   154  
   155  // buildUsingJoin converts a JOIN with a USING clause into an INNER JOIN, LEFT JOIN, or RIGHT JOIN; NATURAL JOINs are a
   156  // subset of USING joins.
   157  // The scope of these join must contain all the qualified columns from both left and right tables. The columns listed
   158  // in the USING clause must be in both left and right tables, and will be redirected to
   159  // either the left or right table.
   160  // An equality filter is created with columns in the USING list. Columns in the USING
   161  // list are de-duplicated and listed first (in the order they appear in the left table), followed by the remaining
   162  // columns from the left table, followed by the remaining columns from the right table.
   163  // NATURAL_JOIN(t1, t2)       => PROJ(t1.a1, ...,t1.aN) -> INNER_JOIN(t1, t2, [t1.a1=t2.a1,..., t1.aN=t2.aN])
   164  // NATURAL_LEFT_JOIN(t1, t2)  => PROJ(t1.a1, ...,t1.aN) -> LEFT_JOIN (t1, t2, [t1.a1=t2.a1,..., t1.aN=t2.aN])
   165  // NATURAL_RIGHT_JOIN(t1, t2) => PROJ(t1.a1, ...,t1.aN) -> RIGHT_JOIN(t1, t2, [t1.a1=t2.a1,..., t1.aN=t2.aN])
   166  // USING_JOIN(t1, t2)         => PROJ(t1.a1, ...,t1.aN) -> INNER_JOIN(t1, t2, [t1.a1=t2.a1,..., t1.aN=t2.aN])
   167  // USING_LEFT_JOIN(t1, t2)    => PROJ(t1.a1, ...,t1.aN) -> LEFT_JOIN (t1, t2, [t1.a1=t2.a1,..., t1.aN=t2.aN])
   168  // USING_RIGHT_JOIN(t1, t2)   => PROJ(t1.a1, ...,t1.aN) -> RIGHT_JOIN(t1, t2, [t1.a1=t2.a1,..., t1.aN=t2.aN])
   169  func (b *Builder) buildUsingJoin(inScope, leftScope, rightScope *scope, te *ast.JoinTableExpr) (outScope *scope) {
   170  	outScope = inScope.push()
   171  
   172  	// Fill in USING columns for NATURAL JOINs
   173  	if len(te.Condition.Using) == 0 {
   174  		for _, lCol := range leftScope.cols {
   175  			for _, rCol := range rightScope.cols {
   176  				if strings.EqualFold(lCol.col, rCol.col) {
   177  					te.Condition.Using = append(te.Condition.Using, ast.NewColIdent(lCol.col))
   178  					break
   179  				}
   180  			}
   181  		}
   182  	}
   183  
   184  	// Right joins swap left and right scopes.
   185  	var left, right *scope
   186  	if te.Join == ast.RightJoinStr || te.Join == ast.NaturalRightJoinStr {
   187  		left, right = rightScope, leftScope
   188  	} else {
   189  		left, right = leftScope, rightScope
   190  	}
   191  
   192  	// Add columns in common
   193  	var filter sql.Expression
   194  	usingCols := map[string]struct{}{}
   195  	for _, col := range te.Condition.Using {
   196  		colName := col.String()
   197  		// Every column in the USING clause must be in both tables.
   198  		lCol, ok := left.resolveColumn("", "", colName, false, false)
   199  		if !ok {
   200  			b.handleErr(sql.ErrUnknownColumn.New(colName, "from clause"))
   201  		}
   202  		rCol, ok := right.resolveColumn("", "", colName, false, false)
   203  		if !ok {
   204  			b.handleErr(sql.ErrUnknownColumn.New(colName, "from clause"))
   205  		}
   206  		f := expression.NewEquals(lCol.scalarGf(), rCol.scalarGf())
   207  		if filter == nil {
   208  			filter = f
   209  		} else {
   210  			filter = expression.NewAnd(filter, f)
   211  		}
   212  		usingCols[colName] = struct{}{}
   213  		outScope.redirect(scopeColumn{col: rCol.col}, lCol)
   214  	}
   215  
   216  	// Add common columns first, then left, then right.
   217  	// The order of columns for the common section must match left table
   218  	for _, lCol := range left.cols {
   219  		if _, ok := usingCols[lCol.col]; ok {
   220  			outScope.addColumn(lCol)
   221  		}
   222  	}
   223  	for _, rCol := range right.cols {
   224  		if _, ok := usingCols[rCol.col]; ok {
   225  			outScope.addColumn(rCol)
   226  		}
   227  	}
   228  	for _, lCol := range left.cols {
   229  		if _, ok := usingCols[lCol.col]; !ok {
   230  			outScope.addColumn(lCol)
   231  		}
   232  	}
   233  	for _, rCol := range right.cols {
   234  		if _, ok := usingCols[rCol.col]; !ok {
   235  			outScope.addColumn(rCol)
   236  		}
   237  	}
   238  
   239  	// joining two tables with no common columns is just cross join
   240  	if len(te.Condition.Using) == 0 {
   241  		if b.isLateral(te.RightExpr) {
   242  			outScope.node = plan.NewJoin(leftScope.node, rightScope.node, plan.JoinTypeLateralCross, nil)
   243  		} else {
   244  			outScope.node = plan.NewCrossJoin(leftScope.node, rightScope.node)
   245  		}
   246  		return outScope
   247  	}
   248  
   249  	switch strings.ToLower(te.Join) {
   250  	case ast.JoinStr, ast.NaturalJoinStr:
   251  		outScope.node = plan.NewInnerJoin(leftScope.node, rightScope.node, filter)
   252  	case ast.LeftJoinStr, ast.NaturalLeftJoinStr:
   253  		outScope.node = plan.NewLeftOuterJoin(leftScope.node, rightScope.node, filter)
   254  	case ast.RightJoinStr, ast.NaturalRightJoinStr:
   255  		outScope.node = plan.NewLeftOuterJoin(rightScope.node, leftScope.node, filter)
   256  	default:
   257  		b.handleErr(fmt.Errorf("unknown using join type: %s", te.Join))
   258  	}
   259  	return outScope
   260  }
   261  
   262  func (b *Builder) buildDataSource(inScope *scope, te ast.TableExpr) (outScope *scope) {
   263  	outScope = inScope.push()
   264  	outScope.ast = te
   265  
   266  	// build individual table, collect column definitions
   267  	switch t := (te).(type) {
   268  	case *ast.AliasedTableExpr:
   269  		switch e := t.Expr.(type) {
   270  		case ast.TableName:
   271  			tableName := strings.ToLower(e.Name.String())
   272  			tAlias := strings.ToLower(t.As.String())
   273  			if cteScope := inScope.getCte(tableName); cteScope != nil {
   274  				outScope = cteScope.aliasCte(tAlias)
   275  				outScope.parent = inScope
   276  			} else {
   277  				var ok bool
   278  				outScope, ok = b.buildTablescan(inScope, e.Qualifier.String(), tableName, t.AsOf)
   279  				if !ok {
   280  					b.handleErr(sql.ErrTableNotFound.New(tableName))
   281  				}
   282  			}
   283  			if tAlias != "" {
   284  				outScope.setTableAlias(tAlias)
   285  				var err error
   286  				outScope.node, err = b.f.buildTableAlias(tAlias, outScope.node.(plan.TableIdNode))
   287  				if err != nil {
   288  					b.handleErr(err)
   289  				}
   290  			}
   291  		case *ast.Subquery:
   292  			if t.As.IsEmpty() {
   293  				// This should be caught by the parser, but here just in case
   294  				b.handleErr(sql.ErrUnsupportedFeature.New("subquery without alias"))
   295  			}
   296  
   297  			sqScope := inScope.pushSubquery()
   298  			fromScope := b.buildSelectStmt(sqScope, e.Select)
   299  			alias := strings.ToLower(t.As.String())
   300  			sq := plan.NewSubqueryAlias(alias, ast.String(e.Select), fromScope.node)
   301  			sq = sq.WithCorrelated(sqScope.correlated())
   302  			sq = sq.WithVolatile(sqScope.volatile())
   303  			sq.IsLateral = t.Lateral
   304  
   305  			var renameCols []string
   306  			if len(e.Columns) > 0 {
   307  				renameCols = columnsToStrings(e.Columns)
   308  				sq = sq.WithColumnNames(renameCols)
   309  			}
   310  
   311  			if len(renameCols) > 0 && len(fromScope.cols) != len(renameCols) {
   312  				err := sql.ErrColumnCountMismatch.New()
   313  				b.handleErr(err)
   314  			}
   315  
   316  			outScope = inScope.push()
   317  			tabId := outScope.addTable(sq.Name())
   318  
   319  			scopeMapping := make(map[sql.ColumnId]sql.Expression)
   320  			var colSet sql.ColSet
   321  			for i, c := range fromScope.cols {
   322  				col := c.col
   323  				if len(renameCols) > 0 {
   324  					col = renameCols[i]
   325  				}
   326  				toId := outScope.newColumn(scopeColumn{
   327  					tableId:     tabId,
   328  					db:          c.db,
   329  					table:       alias,
   330  					col:         col,
   331  					originalCol: c.originalCol,
   332  					id:          0,
   333  					typ:         c.typ,
   334  					nullable:    c.nullable,
   335  				})
   336  				colSet.Add(sql.ColumnId(toId))
   337  				scopeMapping[sql.ColumnId(toId)] = c.scalarGf()
   338  			}
   339  			outScope.node = sq.WithScopeMapping(scopeMapping).WithColumns(colSet).WithId(tabId)
   340  			return
   341  		case *ast.ValuesStatement:
   342  			if t.As.IsEmpty() {
   343  				// Parser should enforce this, but just to be safe
   344  				b.handleErr(sql.ErrUnsupportedSyntax.New("every derived table must have an alias"))
   345  			}
   346  			exprTuples := make([][]sql.Expression, len(e.Rows))
   347  			for i, vt := range e.Rows {
   348  				exprs := make([]sql.Expression, len(vt))
   349  				exprTuples[i] = exprs
   350  				for j, e := range vt {
   351  					exprs[j] = b.buildScalar(inScope, e)
   352  				}
   353  			}
   354  
   355  			outScope = inScope.push()
   356  			vdt := plan.NewValueDerivedTable(plan.NewValues(exprTuples), t.As.String())
   357  			tableName := strings.ToLower(t.As.String())
   358  			tabId := outScope.addTable(tableName)
   359  			var cols sql.ColSet
   360  			for _, c := range vdt.Schema() {
   361  				id := outScope.newColumn(scopeColumn{col: c.Name, db: c.DatabaseSource, table: tableName, typ: c.Type, nullable: c.Nullable})
   362  				cols.Add(sql.ColumnId(id))
   363  			}
   364  			var renameCols []string
   365  			if len(e.Columns) > 0 {
   366  				renameCols = columnsToStrings(e.Columns)
   367  				vdt = vdt.WithColumNames(renameCols)
   368  			}
   369  			b.renameSource(outScope, tableName, renameCols)
   370  			outScope.node = vdt.WithId(tabId).WithColumns(cols)
   371  			return
   372  		default:
   373  			b.handleErr(sql.ErrUnsupportedSyntax.New(ast.String(te)))
   374  		}
   375  
   376  	case *ast.TableFuncExpr:
   377  		return b.buildTableFunc(inScope, t)
   378  
   379  	case *ast.JoinTableExpr:
   380  		return b.buildJoin(inScope, t)
   381  
   382  	case *ast.JSONTableExpr:
   383  		return b.buildJSONTable(inScope, t)
   384  
   385  	case *ast.ParenTableExpr:
   386  		if len(t.Exprs) == 1 {
   387  			switch j := t.Exprs[0].(type) {
   388  			case *ast.JoinTableExpr:
   389  				return b.buildJoin(inScope, j)
   390  			default:
   391  				b.handleErr(sql.ErrUnsupportedSyntax.New(ast.String(t)))
   392  			}
   393  		} else {
   394  			b.handleErr(sql.ErrUnsupportedSyntax.New(ast.String(t)))
   395  		}
   396  	default:
   397  		b.handleErr(sql.ErrUnsupportedSyntax.New(ast.String(te)))
   398  	}
   399  	return
   400  }
   401  
   402  func columnsToStrings(cols ast.Columns) []string {
   403  	if len(cols) == 0 {
   404  		return nil
   405  	}
   406  	res := make([]string, len(cols))
   407  	for i, c := range cols {
   408  		res[i] = c.String()
   409  	}
   410  
   411  	return res
   412  }
   413  
   414  func (b *Builder) resolveTable(tab, db string, asOf interface{}) *plan.ResolvedTable {
   415  	var table sql.Table
   416  	var database sql.Database
   417  	var err error
   418  	if asOf != nil {
   419  		table, database, err = b.cat.TableAsOf(b.ctx, db, tab, asOf)
   420  	} else {
   421  		table, database, err = b.cat.Table(b.ctx, db, tab)
   422  	}
   423  	if sql.ErrAsOfNotSupported.Is(err) {
   424  		if asOf != nil {
   425  			b.handleErr(err)
   426  		}
   427  		table, database, err = b.cat.Table(b.ctx, db, tab)
   428  	}
   429  	if err != nil {
   430  		b.handleErr(err)
   431  	}
   432  
   433  	if privilegedDatabase, ok := database.(mysql_db.PrivilegedDatabase); ok {
   434  		database = privilegedDatabase.Unwrap()
   435  	}
   436  	return plan.NewResolvedTable(table, database, asOf)
   437  }
   438  
   439  func (b *Builder) buildTableFunc(inScope *scope, t *ast.TableFuncExpr) (outScope *scope) {
   440  	//TODO what are valid mysql table arguments
   441  	args := make([]sql.Expression, 0, len(t.Exprs))
   442  	for _, e := range t.Exprs {
   443  		switch e := e.(type) {
   444  		case *ast.AliasedExpr:
   445  			expr := b.buildScalar(inScope, e.Expr)
   446  
   447  			if !e.As.IsEmpty() {
   448  				b.handleErr(sql.ErrUnsupportedSyntax.New(ast.String(e)))
   449  			}
   450  
   451  			if selectExprNeedsAlias(e, expr) {
   452  				b.handleErr(sql.ErrUnsupportedSyntax.New(ast.String(e)))
   453  			}
   454  
   455  			args = append(args, expr)
   456  		default:
   457  			b.handleErr(sql.ErrUnsupportedSyntax.New(ast.String(e)))
   458  		}
   459  	}
   460  
   461  	utf := expression.NewUnresolvedTableFunction(t.Name, args)
   462  
   463  	tableFunction, err := b.cat.TableFunction(b.ctx, utf.Name())
   464  	if err != nil {
   465  		b.handleErr(err)
   466  	}
   467  
   468  	database := b.currentDb()
   469  
   470  	var hasBindVarArgs bool
   471  	for _, arg := range utf.Arguments {
   472  		if _, ok := arg.(*expression.BindVar); ok {
   473  			hasBindVarArgs = true
   474  			break
   475  		}
   476  	}
   477  
   478  	outScope = inScope.push()
   479  	outScope.ast = t
   480  	if hasBindVarArgs {
   481  		// TODO deferred tableFunction
   482  	}
   483  
   484  	newInstance, err := tableFunction.NewInstance(b.ctx, database, utf.Arguments)
   485  	if err != nil {
   486  		b.handleErr(err)
   487  	}
   488  
   489  	if ctf, isCTF := newInstance.(sql.CatalogTableFunction); isCTF {
   490  		newInstance, err = ctf.WithCatalog(b.cat)
   491  		if err != nil {
   492  			b.handleErr(err)
   493  		}
   494  	}
   495  
   496  	// Table Function must always have an alias, pick function name as alias if none is provided
   497  	var name string
   498  	var newAlias plan.TableIdNode
   499  	if t.Alias.IsEmpty() {
   500  		name = t.Name
   501  		newAlias = plan.NewTableAlias(name, newInstance)
   502  	} else {
   503  		name = t.Alias.String()
   504  		newAlias, err = b.f.buildTableAlias(name, newInstance)
   505  		if err != nil {
   506  			b.handleErr(err)
   507  		}
   508  	}
   509  
   510  	tabId := outScope.addTable(name)
   511  	var colset sql.ColSet
   512  	for _, c := range newAlias.Schema() {
   513  		id := outScope.newColumn(scopeColumn{
   514  			db:    database.Name(),
   515  			table: name,
   516  			col:   c.Name,
   517  			typ:   c.Type,
   518  		})
   519  		colset.Add(sql.ColumnId(id))
   520  	}
   521  	outScope.node = newAlias.WithColumns(colset).WithId(tabId)
   522  	return
   523  }
   524  
   525  func (b *Builder) buildJSONTableCols(inScope *scope, jtSpec *ast.JSONTableSpec) []plan.JSONTableCol {
   526  	var cols []plan.JSONTableCol
   527  	for _, jtColDef := range jtSpec.Columns {
   528  		// nested col defs need to be flattened into multiple colOpts with all paths appended
   529  		if jtColDef.Spec != nil {
   530  			nestedCols := b.buildJSONTableCols(inScope, jtColDef.Spec)
   531  			col := plan.JSONTableCol{
   532  				Path:       jtColDef.Spec.Path,
   533  				NestedCols: nestedCols,
   534  			}
   535  			cols = append(cols, col)
   536  			continue
   537  		}
   538  
   539  		typ, err := types.ColumnTypeToType(&jtColDef.Type)
   540  		if err != nil {
   541  			b.handleErr(err)
   542  		}
   543  
   544  		var defEmptyVal, defErrorVal sql.Expression
   545  		if jtColDef.Opts.ValOnEmpty == nil {
   546  			defEmptyVal = expression.NewLiteral(nil, types.Null)
   547  		} else {
   548  			defEmptyVal = b.buildScalar(inScope, jtColDef.Opts.ValOnEmpty)
   549  		}
   550  
   551  		if jtColDef.Opts.ValOnError == nil {
   552  			defErrorVal = expression.NewLiteral(nil, types.Null)
   553  		} else {
   554  			defErrorVal = b.buildScalar(inScope, jtColDef.Opts.ValOnError)
   555  		}
   556  
   557  		col := plan.JSONTableCol{
   558  			Path: jtColDef.Opts.Path,
   559  			Opts: &plan.JSONTableColOpts{
   560  				Name:         jtColDef.Name.String(),
   561  				Type:         typ,
   562  				ForOrd:       bool(jtColDef.Type.Autoincrement),
   563  				Exists:       jtColDef.Opts.Exists,
   564  				DefEmptyVal:  defEmptyVal,
   565  				DefErrorVal:  defErrorVal,
   566  				ErrorOnEmpty: jtColDef.Opts.ErrorOnEmpty,
   567  				ErrorOnError: jtColDef.Opts.ErrorOnError,
   568  			},
   569  		}
   570  		cols = append(cols, col)
   571  	}
   572  	return cols
   573  }
   574  
   575  func (b *Builder) buildJSONTable(inScope *scope, t *ast.JSONTableExpr) (outScope *scope) {
   576  	data := b.buildScalar(inScope, t.Data)
   577  	if _, ok := data.(*plan.Subquery); ok {
   578  		b.handleErr(sql.ErrInvalidArgument.New("JSON_TABLE"))
   579  	}
   580  
   581  	outScope = inScope.push()
   582  	outScope.ast = t
   583  
   584  	alias := strings.ToLower(t.Alias.String())
   585  	tabId := outScope.addTable(alias)
   586  	cols := b.buildJSONTableCols(inScope, t.Spec)
   587  	var colset sql.ColSet
   588  	var recFlatten func(col plan.JSONTableCol)
   589  	recFlatten = func(col plan.JSONTableCol) {
   590  		for _, col := range col.NestedCols {
   591  			recFlatten(col)
   592  		}
   593  		if col.Opts != nil {
   594  			id := outScope.newColumn(scopeColumn{
   595  				table: alias,
   596  				col:   col.Opts.Name,
   597  				typ:   col.Opts.Type,
   598  			})
   599  			colset.Add(sql.ColumnId(id))
   600  		}
   601  	}
   602  	for _, col := range cols {
   603  		recFlatten(col)
   604  	}
   605  
   606  	var err error
   607  	jt, err := plan.NewJSONTable(data, t.Spec.Path, alias, cols)
   608  	if err != nil {
   609  		b.handleErr(err)
   610  	}
   611  
   612  	outScope.node = jt.WithColumns(colset).WithId(tabId)
   613  	return outScope
   614  }
   615  
   616  func (b *Builder) buildTablescan(inScope *scope, db, name string, asof *ast.AsOf) (outScope *scope, ok bool) {
   617  	return b.buildResolvedTable(inScope, db, name, asof)
   618  }
   619  
   620  func (b *Builder) buildResolvedTable(inScope *scope, db, name string, asof *ast.AsOf) (outScope *scope, ok bool) {
   621  	outScope = inScope.push()
   622  
   623  	if db == "" && b.ViewCtx().DbName != "" {
   624  		db = b.ViewCtx().DbName
   625  	} else if db == "" {
   626  		db = b.ctx.GetCurrentDatabase()
   627  	}
   628  
   629  	var asOfLit interface{}
   630  	if asof != nil {
   631  		asOfLit = b.buildAsOfLit(inScope, asof.Time)
   632  	} else if asof := b.ViewCtx().AsOf; asof != nil {
   633  		asOfLit = asof
   634  	} else if asof := b.ProcCtx().AsOf; asof != nil {
   635  		asOfLit = asof
   636  	}
   637  
   638  	var tab sql.Table
   639  	var database sql.Database
   640  	var err error
   641  	database, err = b.cat.Database(b.ctx, db)
   642  	if err != nil {
   643  		b.handleErr(err)
   644  	}
   645  
   646  	if view := b.resolveView(name, database, asOfLit); view != nil {
   647  		outScope.node = view
   648  		tabId := outScope.addTable(strings.ToLower(view.Schema()[0].Name))
   649  		var cols sql.ColSet
   650  		for _, c := range view.Schema() {
   651  			id := outScope.newColumn(scopeColumn{
   652  				db:          db,
   653  				table:       name,
   654  				col:         strings.ToLower(c.Name),
   655  				originalCol: c.Name,
   656  				typ:         c.Type,
   657  				nullable:    c.Nullable,
   658  			})
   659  			cols.Add(sql.ColumnId(id))
   660  		}
   661  		if tin, ok := view.(plan.TableIdNode); ok {
   662  			// TODO should *sql.View implement TableIdNode?
   663  			outScope.node = tin.WithId(tabId).WithColumns(cols)
   664  		}
   665  
   666  		return outScope, true
   667  	}
   668  
   669  	if asOfLit != nil {
   670  		tab, database, err = b.cat.TableAsOf(b.ctx, db, name, asOfLit)
   671  	} else {
   672  		tab, _, err = database.GetTableInsensitive(b.ctx, name)
   673  	}
   674  	if err != nil {
   675  		if sql.ErrDatabaseNotFound.Is(err) {
   676  			if db == "" {
   677  				err = sql.ErrNoDatabaseSelected.New()
   678  			}
   679  		}
   680  		b.handleErr(err)
   681  	} else if tab == nil {
   682  		if b.TriggerCtx().Active && !b.TriggerCtx().Call {
   683  			outScope.node = plan.NewUnresolvedTable(name, db)
   684  			b.TriggerCtx().UnresolvedTables = append(b.TriggerCtx().UnresolvedTables, name)
   685  			return outScope, true
   686  		}
   687  		return outScope, false
   688  	}
   689  
   690  	// TODO: this is maybe too broad for this method, we don't need this for some statements
   691  	if tab.Schema().HasVirtualColumns() {
   692  		tab = b.buildVirtualTableScan(db, tab)
   693  	}
   694  
   695  	rt := plan.NewResolvedTable(tab, database, asOfLit)
   696  	ct, ok := rt.Table.(sql.CatalogTable)
   697  	if ok {
   698  		rt.Table = ct.AssignCatalog(b.cat)
   699  	}
   700  
   701  	tabId := outScope.addTable(strings.ToLower(tab.Name()))
   702  	var cols sql.ColSet
   703  
   704  	for _, c := range tab.Schema() {
   705  		id := outScope.newColumn(scopeColumn{
   706  			db:          db,
   707  			table:       strings.ToLower(tab.Name()),
   708  			col:         strings.ToLower(c.Name),
   709  			originalCol: c.Name,
   710  			typ:         c.Type,
   711  			nullable:    c.Nullable,
   712  		})
   713  		cols.Add(sql.ColumnId(id))
   714  	}
   715  
   716  	rt = rt.WithId(tabId).WithColumns(cols).(*plan.ResolvedTable)
   717  	outScope.node = rt
   718  
   719  	if dt, _ := rt.Table.(sql.DynamicColumnsTable); dt != nil {
   720  		// the columns table has to resolve all columns in every table
   721  		sch, err := dt.AllColumns(b.ctx)
   722  		if err != nil {
   723  			b.handleErr(err)
   724  		}
   725  
   726  		var newSch sql.Schema
   727  		startSource := sch[0].Source
   728  		tmpScope := inScope.push()
   729  		for i, c := range sch {
   730  			// bucket schema fragments into colsets for resolving defaults
   731  			newCol := scopeColumn{
   732  				db:          c.DatabaseSource,
   733  				table:       c.Source,
   734  				col:         strings.ToLower(c.Name),
   735  				originalCol: c.Name,
   736  				typ:         c.Type,
   737  				nullable:    c.Nullable,
   738  			}
   739  			if !strings.EqualFold(c.Source, startSource) {
   740  				startSource = c.Source
   741  				tmpSch := b.resolveSchemaDefaults(tmpScope, sch[i-len(tmpScope.cols):i])
   742  				newSch = append(newSch, tmpSch...)
   743  				tmpScope = inScope.push()
   744  			}
   745  			tmpScope.newColumn(newCol)
   746  		}
   747  		if len(tmpScope.cols) > 0 {
   748  			tmpSch := b.resolveSchemaDefaults(tmpScope, sch[len(sch)-len(tmpScope.cols):len(sch)])
   749  			newSch = append(newSch, tmpSch...)
   750  		}
   751  		rt.Table, err = dt.WithDefaultsSchema(newSch)
   752  		if err != nil {
   753  			b.handleErr(err)
   754  		}
   755  	}
   756  
   757  	return outScope, true
   758  }
   759  
   760  func (b *Builder) resolveView(name string, database sql.Database, asOf interface{}) sql.Node {
   761  	var view *sql.View
   762  
   763  	if vdb, vok := database.(sql.ViewDatabase); vok {
   764  		viewDef, vdok, err := vdb.GetViewDefinition(b.ctx, name)
   765  		if err != nil {
   766  			b.handleErr(err)
   767  		}
   768  		oldOpts := b.parserOpts
   769  		defer func() {
   770  			b.parserOpts = oldOpts
   771  		}()
   772  		if vdok {
   773  			outerAsOf := b.ViewCtx().AsOf
   774  			outerDb := b.ViewCtx().DbName
   775  			b.ViewCtx().AsOf = asOf
   776  			b.ViewCtx().DbName = database.Name()
   777  			defer func() {
   778  				b.ViewCtx().AsOf = outerAsOf
   779  				b.ViewCtx().DbName = outerDb
   780  			}()
   781  			b.parserOpts = sql.NewSqlModeFromString(viewDef.SqlMode).ParserOptions()
   782  			node, _, _, err := b.Parse(viewDef.CreateViewStatement, false)
   783  			if err != nil {
   784  				// TODO: Need to account for non-existing functions or
   785  				//  users without appropriate privilege to the referenced table/column/function.
   786  				if sql.ErrTableNotFound.Is(err) || sql.ErrColumnNotFound.Is(err) {
   787  					// TODO: ALTER VIEW should not return this error
   788  					err = sql.ErrInvalidRefInView.New(database.Name(), name)
   789  				}
   790  				b.handleErr(err)
   791  			}
   792  			create, ok := node.(*plan.CreateView)
   793  			if !ok {
   794  				err = fmt.Errorf("expected create view statement, found: %T", node)
   795  			}
   796  			switch n := create.Child.(type) {
   797  			case *plan.SubqueryAlias:
   798  				view = n.AsView(viewDef.CreateViewStatement)
   799  			default:
   800  				view = plan.NewSubqueryAlias(name, viewDef.TextDefinition, n).AsView(viewDef.CreateViewStatement)
   801  			}
   802  
   803  		}
   804  	}
   805  	// If we didn't find the view from the database directly, use the in-session registry
   806  	if view == nil {
   807  		view, _ = b.ctx.GetViewRegistry().View(database.Name(), name)
   808  		if view != nil {
   809  			def, _, _ := transform.NodeWithOpaque(view.Definition(), func(n sql.Node) (sql.Node, transform.TreeIdentity, error) {
   810  				// TODO this is a hack because the test registry setup is busted, these should always be resolved
   811  				if urt, ok := n.(*plan.UnresolvedTable); ok {
   812  					return b.resolveTable(urt.Name(), urt.Database().Name(), urt.AsOf()), transform.NewTree, nil
   813  				}
   814  				return n, transform.SameTree, nil
   815  			})
   816  			view = view.WithDefinition(def)
   817  		}
   818  	}
   819  
   820  	if view == nil {
   821  		return nil
   822  	}
   823  
   824  	query := view.Definition().Children()[0]
   825  	n, err := view.Definition().WithChildren(query)
   826  	if err != nil {
   827  		b.handleErr(err)
   828  	}
   829  	return n
   830  }