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  }