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 }