// writeTableDesc implements the SchemaAccessor interface. func (p *planner) writeTableDesc(tableDesc *sqlbase.TableDescriptor) error { if isVirtualDescriptor(tableDesc) { panic(fmt.Sprintf("Virtual Descriptors cannot be stored, found: %v", tableDesc)) } return p.txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.GetID()), sqlbase.WrapDescriptor(tableDesc)) }
func (sc *SchemaChanger) maybeWriteResumeSpan( txn *client.Txn, tableDesc *sqlbase.TableDescriptor, resume roachpb.Span, mutationIdx int, lastCheckpoint *time.Time, ) error { checkpointInterval := checkpointInterval if sc.testingKnobs.WriteCheckpointInterval > 0 { checkpointInterval = sc.testingKnobs.WriteCheckpointInterval } if timeutil.Since(*lastCheckpoint) < checkpointInterval { return nil } tableDesc.Mutations[mutationIdx].ResumeSpan = resume txn.SetSystemConfigTrigger() if err := txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.GetID()), sqlbase.WrapDescriptor(tableDesc)); err != nil { return err } *lastCheckpoint = timeutil.Now() return nil }
// RenameTable renames the table or view. // Privileges: DROP on source table/view, CREATE on destination database. // Notes: postgres requires the table owner. // mysql requires ALTER, DROP on the original table, and CREATE, INSERT // on the new table (and does not copy privileges over). func (p *planner) RenameTable(n *parser.RenameTable) (planNode, error) { oldTn, err := n.Name.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } newTn, err := n.NewName.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } dbDesc, err := p.mustGetDatabaseDesc(oldTn.Database()) if err != nil { return nil, err } // Check if source table or view exists. // Note that Postgres's behavior here is a little lenient - it'll let you // modify views by running ALTER TABLE, but won't let you modify tables // by running ALTER VIEW. Our behavior is strict for now, but can be // made more lenient down the road if needed. var tableDesc *sqlbase.TableDescriptor if n.IsView { tableDesc, err = p.getViewDesc(oldTn) if err != nil { return nil, err } if tableDesc == nil { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, sqlbase.NewUndefinedViewError(oldTn.String()) } if tableDesc.State != sqlbase.TableDescriptor_PUBLIC { return nil, sqlbase.NewUndefinedViewError(oldTn.String()) } } else { tableDesc, err = p.getTableDesc(oldTn) if err != nil { return nil, err } if tableDesc == nil { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, sqlbase.NewUndefinedTableError(oldTn.String()) } if tableDesc.State != sqlbase.TableDescriptor_PUBLIC { return nil, sqlbase.NewUndefinedTableError(oldTn.String()) } } if err := p.checkPrivilege(tableDesc, privilege.DROP); err != nil { return nil, err } // Check if any views depend on this table/view. Because our views // are currently just stored as strings, they explicitly specify the name // of everything they depend on. Rather than trying to rewrite the view's // query with the new name, we simply disallow such renames for now. if len(tableDesc.DependedOnBy) > 0 { return nil, p.dependentViewRenameError( tableDesc.TypeName(), oldTn.String(), tableDesc.ParentID, tableDesc.DependedOnBy[0].ID) } // Check if target database exists. targetDbDesc, err := p.mustGetDatabaseDesc(newTn.Database()) if err != nil { return nil, err } if err := p.checkPrivilege(targetDbDesc, privilege.CREATE); err != nil { return nil, err } // oldTn and newTn are already normalized, so we can compare directly here. if oldTn.Database() == newTn.Database() && oldTn.Table() == newTn.Table() { // Noop. return &emptyNode{}, nil } tableDesc.SetName(newTn.Table()) tableDesc.ParentID = targetDbDesc.ID descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) newTbKey := tableKey{targetDbDesc.ID, newTn.Table()}.Key() if err := tableDesc.Validate(p.txn); err != nil { return nil, err } descID := tableDesc.GetID() descDesc := sqlbase.WrapDescriptor(tableDesc) if err := tableDesc.SetUpVersion(); err != nil { return nil, err } renameDetails := sqlbase.TableDescriptor_RenameInfo{ OldParentID: dbDesc.ID, OldName: oldTn.Table()} tableDesc.Renames = append(tableDesc.Renames, renameDetails) if err := p.writeTableDesc(tableDesc); err != nil { return nil, err } // We update the descriptor to the new name, but also leave the mapping of the // old name to the id, so that the name is not reused until the schema changer // has made sure it's not in use any more. b := &client.Batch{} b.Put(descKey, descDesc) b.CPut(newTbKey, descID, nil) if err := p.txn.Run(b); err != nil { if _, ok := err.(*roachpb.ConditionFailedError); ok { return nil, sqlbase.NewRelationAlreadyExistsError(newTn.Table()) } return nil, err } p.notifySchemaChange(tableDesc.ID, sqlbase.InvalidMutationID) p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, newTbKey, descID); err != nil { return err } if err := expectDescriptor(systemConfig, descKey, descDesc); err != nil { return err } return nil }) return &emptyNode{}, nil }