github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/optbuilder/create_table.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package optbuilder
    12  
    13  import (
    14  	"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
    15  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical"
    16  	"github.com/cockroachdb/cockroach/pkg/sql/sem/builtins"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    20  	"github.com/cockroachdb/cockroach/pkg/util"
    21  )
    22  
    23  // buildCreateTable constructs a CreateTable operator based on the CREATE TABLE
    24  // statement.
    25  func (b *Builder) buildCreateTable(ct *tree.CreateTable, inScope *scope) (outScope *scope) {
    26  	b.DisableMemoReuse = true
    27  	isTemp := resolveTemporaryStatus(&ct.Table, ct.Temporary)
    28  	if isTemp {
    29  		// Postgres allows using `pg_temp` as an alias for the session specific temp
    30  		// schema. In PG, the following are equivalent:
    31  		// CREATE TEMP TABLE t <=> CREATE TABLE pg_temp.t <=> CREATE TEMP TABLE pg_temp.t
    32  		//
    33  		// The temporary schema is created the first time a session creates
    34  		// a temporary object, so it is possible to use `pg_temp` in a fully
    35  		// qualified name when the temporary schema does not exist. To allow this,
    36  		// we explicitly set the SchemaName to `public` for temporary tables, as
    37  		// the public schema is guaranteed to exist. This ensures the FQN can be
    38  		// resolved correctly.
    39  		// TODO(solon): Once it is possible to drop schemas, it will no longer be
    40  		// safe to set the schema name to `public`, as it may have been dropped.
    41  		ct.Table.ObjectNamePrefix.SchemaName = tree.PublicSchemaName
    42  		ct.Temporary = true
    43  	}
    44  	sch, resName := b.resolveSchemaForCreate(&ct.Table)
    45  	ct.Table.ObjectNamePrefix = resName
    46  	schID := b.factory.Metadata().AddSchema(sch)
    47  
    48  	// HoistConstraints normalizes any column constraints in the CreateTable AST
    49  	// node.
    50  	ct.HoistConstraints()
    51  
    52  	var input memo.RelExpr
    53  	var inputCols physical.Presentation
    54  	if ct.As() {
    55  		// The execution code might need to stringify the query to run it
    56  		// asynchronously. For that we need the data sources to be fully qualified.
    57  		// TODO(radu): this interaction is pretty hacky, investigate moving the
    58  		// generation of the string to the optimizer.
    59  		b.qualifyDataSourceNamesInAST = true
    60  		defer func() {
    61  			b.qualifyDataSourceNamesInAST = false
    62  		}()
    63  
    64  		b.pushWithFrame()
    65  		// Build the input query.
    66  		outScope = b.buildStmt(ct.AsSource, nil /* desiredTypes */, inScope)
    67  		b.popWithFrame(outScope)
    68  
    69  		numColNames := 0
    70  		for i := 0; i < len(ct.Defs); i++ {
    71  			if _, ok := ct.Defs[i].(*tree.ColumnTableDef); ok {
    72  				numColNames++
    73  			}
    74  		}
    75  		numColumns := len(outScope.cols)
    76  		if numColNames != 0 && numColNames != numColumns {
    77  			panic(sqlbase.NewSyntaxErrorf(
    78  				"CREATE TABLE specifies %d column name%s, but data source has %d column%s",
    79  				numColNames, util.Pluralize(int64(numColNames)),
    80  				numColumns, util.Pluralize(int64(numColumns))))
    81  		}
    82  
    83  		input = outScope.expr
    84  		if !ct.AsHasUserSpecifiedPrimaryKey() {
    85  			// Synthesize rowid column, and append to end of column list.
    86  			props, overloads := builtins.GetBuiltinProperties("unique_rowid")
    87  			private := &memo.FunctionPrivate{
    88  				Name:       "unique_rowid",
    89  				Typ:        types.Int,
    90  				Properties: props,
    91  				Overload:   &overloads[0],
    92  			}
    93  			fn := b.factory.ConstructFunction(memo.EmptyScalarListExpr, private)
    94  			scopeCol := b.synthesizeColumn(outScope, "rowid", types.Int, nil /* expr */, fn)
    95  			input = b.factory.CustomFuncs().ProjectExtraCol(outScope.expr, fn, scopeCol.id)
    96  		}
    97  		inputCols = outScope.makePhysicalProps().Presentation
    98  	} else {
    99  		// Create dummy empty input.
   100  		input = b.factory.ConstructZeroValues()
   101  	}
   102  
   103  	outScope = b.allocScope()
   104  	outScope.expr = b.factory.ConstructCreateTable(
   105  		input,
   106  		&memo.CreateTablePrivate{
   107  			Schema:    schID,
   108  			InputCols: inputCols,
   109  			Syntax:    ct,
   110  		},
   111  	)
   112  	return outScope
   113  }