github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/importccl/import_table_creation.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Licensed as a CockroachDB Enterprise file under the Cockroach Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt 8 9 package importccl 10 11 import ( 12 "context" 13 "fmt" 14 "io/ioutil" 15 "strings" 16 17 "github.com/cockroachdb/cockroach/pkg/keys" 18 "github.com/cockroachdb/cockroach/pkg/kv" 19 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 20 "github.com/cockroachdb/cockroach/pkg/sql" 21 "github.com/cockroachdb/cockroach/pkg/sql/catalog" 22 "github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver" 23 "github.com/cockroachdb/cockroach/pkg/sql/parser" 24 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 25 "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" 26 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 27 "github.com/cockroachdb/cockroach/pkg/storage/cloud" 28 "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented" 29 "github.com/cockroachdb/cockroach/pkg/util/hlc" 30 "github.com/cockroachdb/errors" 31 ) 32 33 const ( 34 // We need to choose arbitrary database and table IDs. These aren't important, 35 // but they do match what would happen when creating a new database and 36 // table on an empty cluster. 37 defaultCSVParentID sqlbase.ID = keys.MinNonPredefinedUserDescID 38 defaultCSVTableID sqlbase.ID = defaultCSVParentID + 1 39 ) 40 41 func readCreateTableFromStore( 42 ctx context.Context, filename string, externalStorageFromURI cloud.ExternalStorageFromURIFactory, 43 ) (*tree.CreateTable, error) { 44 store, err := externalStorageFromURI(ctx, filename) 45 if err != nil { 46 return nil, err 47 } 48 defer store.Close() 49 reader, err := store.ReadFile(ctx, "") 50 if err != nil { 51 return nil, err 52 } 53 defer reader.Close() 54 tableDefStr, err := ioutil.ReadAll(reader) 55 if err != nil { 56 return nil, err 57 } 58 stmts, err := parser.Parse(string(tableDefStr)) 59 if err != nil { 60 return nil, err 61 } 62 if len(stmts) != 1 { 63 return nil, errors.Errorf("expected 1 create table statement, found %d", len(stmts)) 64 } 65 create, ok := stmts[0].AST.(*tree.CreateTable) 66 if !ok { 67 return nil, errors.New("expected CREATE TABLE statement in table file") 68 } 69 return create, nil 70 } 71 72 type fkHandler struct { 73 allowed bool 74 skip bool 75 resolver fkResolver 76 } 77 78 // NoFKs is used by formats that do not support FKs. 79 var NoFKs = fkHandler{resolver: make(fkResolver)} 80 81 // MakeSimpleTableDescriptor creates a MutableTableDescriptor from a CreateTable parse 82 // node without the full machinery. Many parts of the syntax are unsupported 83 // (see the implementation and TestMakeSimpleTableDescriptorErrors for details), 84 // but this is enough for our csv IMPORT and for some unit tests. 85 // 86 // Any occurrence of SERIAL in the column definitions is handled using 87 // the CockroachDB legacy behavior, i.e. INT NOT NULL DEFAULT 88 // unique_rowid(). 89 func MakeSimpleTableDescriptor( 90 ctx context.Context, 91 st *cluster.Settings, 92 create *tree.CreateTable, 93 parentID, tableID sqlbase.ID, 94 fks fkHandler, 95 walltime int64, 96 ) (*sqlbase.MutableTableDescriptor, error) { 97 create.HoistConstraints() 98 if create.IfNotExists { 99 return nil, unimplemented.NewWithIssueDetailf(42846, "import.if-no-exists", "unsupported IF NOT EXISTS") 100 } 101 if create.Interleave != nil { 102 return nil, unimplemented.NewWithIssueDetailf(42846, "import.interleave", "interleaved not supported") 103 } 104 if create.AsSource != nil { 105 return nil, unimplemented.NewWithIssueDetailf(42846, "import.create-as", "CREATE AS not supported") 106 } 107 108 filteredDefs := create.Defs[:0] 109 for i := range create.Defs { 110 switch def := create.Defs[i].(type) { 111 case *tree.CheckConstraintTableDef, 112 *tree.FamilyTableDef, 113 *tree.IndexTableDef, 114 *tree.UniqueConstraintTableDef: 115 // ignore 116 case *tree.ColumnTableDef: 117 if def.Computed.Expr != nil { 118 return nil, unimplemented.NewWithIssueDetailf(42846, "import.computed", 119 "computed columns not supported: %s", tree.AsString(def)) 120 } 121 122 if err := sql.SimplifySerialInColumnDefWithRowID(ctx, def, &create.Table); err != nil { 123 return nil, err 124 } 125 126 case *tree.ForeignKeyConstraintTableDef: 127 if !fks.allowed { 128 return nil, unimplemented.NewWithIssueDetailf(42846, "import.fk", 129 "this IMPORT format does not support foreign keys") 130 } 131 if fks.skip { 132 continue 133 } 134 // Strip the schema/db prefix. 135 def.Table = tree.MakeUnqualifiedTableName(def.Table.ObjectName) 136 137 default: 138 return nil, unimplemented.Newf(fmt.Sprintf("import.%T", def), "unsupported table definition: %s", tree.AsString(def)) 139 } 140 // only append this def after we make it past the error checks and continues 141 filteredDefs = append(filteredDefs, create.Defs[i]) 142 } 143 create.Defs = filteredDefs 144 145 semaCtx := tree.MakeSemaContext() 146 evalCtx := tree.EvalContext{ 147 Context: ctx, 148 Sequence: &importSequenceOperators{}, 149 } 150 affected := make(map[sqlbase.ID]*sqlbase.MutableTableDescriptor) 151 152 tableDesc, err := sql.MakeTableDesc( 153 ctx, 154 nil, /* txn */ 155 fks.resolver, 156 st, 157 create, 158 parentID, 159 keys.PublicSchemaID, 160 tableID, 161 hlc.Timestamp{WallTime: walltime}, 162 sqlbase.NewDefaultPrivilegeDescriptor(), 163 affected, 164 &semaCtx, 165 &evalCtx, 166 &sessiondata.SessionData{}, /* sessionData */ 167 false, /* temporary */ 168 ) 169 if err != nil { 170 return nil, err 171 } 172 if err := fixDescriptorFKState(tableDesc.TableDesc()); err != nil { 173 return nil, err 174 } 175 176 return &tableDesc, nil 177 } 178 179 // fixDescriptorFKState repairs validity and table states set during descriptor 180 // creation. sql.MakeTableDesc and ResolveFK set the table to the ADD state 181 // and mark references an validated. This function sets the table to PUBLIC 182 // and the FKs to unvalidated. 183 func fixDescriptorFKState(tableDesc *sqlbase.TableDescriptor) error { 184 tableDesc.State = sqlbase.TableDescriptor_PUBLIC 185 for i := range tableDesc.OutboundFKs { 186 tableDesc.OutboundFKs[i].Validity = sqlbase.ConstraintValidity_Unvalidated 187 } 188 return nil 189 } 190 191 var ( 192 errSequenceOperators = errors.New("sequence operations unsupported") 193 errSchemaResolver = errors.New("schema resolver unsupported") 194 ) 195 196 // Implements the tree.SequenceOperators interface. 197 type importSequenceOperators struct { 198 } 199 200 // Implements the tree.EvalDatabase interface. 201 func (so *importSequenceOperators) ParseQualifiedTableName(sql string) (*tree.TableName, error) { 202 name, err := parser.ParseTableName(sql) 203 if err != nil { 204 return nil, err 205 } 206 tn := name.ToTableName() 207 return &tn, nil 208 } 209 210 // Implements the tree.EvalDatabase interface. 211 func (so *importSequenceOperators) ResolveTableName( 212 ctx context.Context, tn *tree.TableName, 213 ) (tree.ID, error) { 214 return 0, errSequenceOperators 215 } 216 217 // Implements the tree.EvalDatabase interface. 218 func (so *importSequenceOperators) LookupSchema( 219 ctx context.Context, dbName, scName string, 220 ) (bool, tree.SchemaMeta, error) { 221 return false, nil, errSequenceOperators 222 } 223 224 // Implements the tree.SequenceOperators interface. 225 func (so *importSequenceOperators) IncrementSequence( 226 ctx context.Context, seqName *tree.TableName, 227 ) (int64, error) { 228 return 0, errSequenceOperators 229 } 230 231 // Implements the tree.SequenceOperators interface. 232 func (so *importSequenceOperators) GetLatestValueInSessionForSequence( 233 ctx context.Context, seqName *tree.TableName, 234 ) (int64, error) { 235 return 0, errSequenceOperators 236 } 237 238 // Implements the tree.SequenceOperators interface. 239 func (so *importSequenceOperators) SetSequenceValue( 240 ctx context.Context, seqName *tree.TableName, newVal int64, isCalled bool, 241 ) error { 242 return errSequenceOperators 243 } 244 245 type fkResolver map[string]*sqlbase.MutableTableDescriptor 246 247 var _ resolver.SchemaResolver = fkResolver{} 248 249 // Implements the sql.SchemaResolver interface. 250 func (r fkResolver) Txn() *kv.Txn { 251 return nil 252 } 253 254 // Implements the sql.SchemaResolver interface. 255 func (r fkResolver) LogicalSchemaAccessor() catalog.Accessor { 256 return nil 257 } 258 259 // Implements the sql.SchemaResolver interface. 260 func (r fkResolver) CurrentDatabase() string { 261 return "" 262 } 263 264 // Implements the sql.SchemaResolver interface. 265 func (r fkResolver) CurrentSearchPath() sessiondata.SearchPath { 266 return sessiondata.SearchPath{} 267 } 268 269 // Implements the sql.SchemaResolver interface. 270 func (r fkResolver) CommonLookupFlags(required bool) tree.CommonLookupFlags { 271 return tree.CommonLookupFlags{} 272 } 273 274 // Implements the sql.SchemaResolver interface. 275 func (r fkResolver) ObjectLookupFlags(required bool, requireMutable bool) tree.ObjectLookupFlags { 276 return tree.ObjectLookupFlags{ 277 CommonLookupFlags: tree.CommonLookupFlags{Required: required}, 278 RequireMutable: requireMutable, 279 } 280 } 281 282 // Implements the tree.ObjectNameExistingResolver interface. 283 func (r fkResolver) LookupObject( 284 ctx context.Context, lookupFlags tree.ObjectLookupFlags, dbName, scName, obName string, 285 ) (found bool, objMeta tree.NameResolutionResult, err error) { 286 if scName != "" { 287 obName = strings.TrimPrefix(obName, scName+".") 288 } 289 tbl, ok := r[obName] 290 if ok { 291 return true, tbl, nil 292 } 293 names := make([]string, 0, len(r)) 294 for k := range r { 295 names = append(names, k) 296 } 297 suggestions := strings.Join(names, ",") 298 return false, nil, errors.Errorf("referenced table %q not found in tables being imported (%s)", obName, suggestions) 299 } 300 301 // Implements the tree.ObjectNameTargetResolver interface. 302 func (r fkResolver) LookupSchema( 303 ctx context.Context, dbName, scName string, 304 ) (found bool, scMeta tree.SchemaMeta, err error) { 305 return false, nil, errSchemaResolver 306 } 307 308 // Implements the sql.SchemaResolver interface. 309 func (r fkResolver) LookupTableByID( 310 ctx context.Context, id sqlbase.ID, 311 ) (catalog.TableEntry, error) { 312 return catalog.TableEntry{}, errSchemaResolver 313 }