// ShowTables returns all the tables. // Privileges: None. // Notes: postgres does not have a SHOW TABLES statement. // mysql only returns tables you have privileges on. func (p *planner) ShowTables(n *parser.ShowTables) (planNode, error) { // TODO(pmattis): This could be implemented as: // // SELECT name FROM system.namespace // WHERE parentID = (SELECT id FROM system.namespace // WHERE parentID = 0 AND name = <database>) name := n.Name if name == nil { if p.session.Database == "" { return nil, errNoDatabase } name = &parser.QualifiedName{Base: parser.Name(p.session.Database)} } dbDesc, err := p.getDatabaseDesc(string(name.Base)) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(string(name.Base)) } tableNames, err := p.getTableNames(dbDesc) if err != nil { return nil, err } v := &valuesNode{columns: []ResultColumn{{Name: "Table", Typ: parser.TypeString}}} for _, name := range tableNames { v.rows = append(v.rows, []parser.Datum{parser.NewDString(name.Table())}) } return v, nil }
// getDatabaseID implements the DatabaseAccessor interface. func (p *planner) getDatabaseID(name string) (sqlbase.ID, error) { if id := p.databaseCache.getID(name); id != 0 { return id, nil } // Lookup the database in the cache first, falling back to the KV store if it // isn't present. The cache might cause the usage of a recently renamed // database, but that's a race that could occur anyways. desc, err := p.getCachedDatabaseDesc(name) if err != nil { if log.V(3) { log.Infof("%v", err) } var err error desc, err = p.getDatabaseDesc(name) if err != nil { return 0, err } if desc == nil { return 0, sqlbase.NewUndefinedDatabaseError(name) } } p.databaseCache.setID(name, desc.ID) return desc.ID, nil }
// expandTableGlob implements the SchemaAccessor interface. func (p *planner) expandTableGlob(expr *parser.QualifiedName) ( parser.QualifiedNames, error) { if len(expr.Indirect) == 0 { return parser.QualifiedNames{expr}, nil } if err := expr.QualifyWithDatabase(p.session.Database); err != nil { return nil, err } // We must have a single indirect: either .table or .* if len(expr.Indirect) != 1 { return nil, fmt.Errorf("invalid table glob: %s", expr) } switch expr.Indirect[0].(type) { case parser.NameIndirection: return parser.QualifiedNames{expr}, nil case parser.StarIndirection: dbDesc, err := p.getDatabaseDesc(string(expr.Base)) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(string(expr.Base)) } tableNames, err := p.getTableNames(dbDesc) if err != nil { return nil, err } return tableNames, nil default: return nil, fmt.Errorf("invalid table glob: %s", expr) } }
// RenameDatabase renames the database. // Privileges: security.RootUser user. // Notes: postgres requires superuser, db owner, or "CREATEDB". // mysql >= 5.1.23 does not allow database renames. func (p *planner) RenameDatabase(n *parser.RenameDatabase) (planNode, error) { if n.Name == "" || n.NewName == "" { return nil, errEmptyDatabaseName } if p.session.User != security.RootUser { return nil, fmt.Errorf("only %s is allowed to rename databases", security.RootUser) } dbDesc, err := p.getDatabaseDesc(string(n.Name)) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(string(n.Name)) } if n.Name == n.NewName { // Noop. return &emptyNode{}, nil } // Now update the nameMetadataKey and the descriptor. descKey := sqlbase.MakeDescMetadataKey(dbDesc.GetID()) dbDesc.SetName(string(n.NewName)) if err := dbDesc.Validate(); err != nil { return nil, err } newKey := databaseKey{string(n.NewName)}.Key() oldKey := databaseKey{string(n.Name)}.Key() descID := dbDesc.GetID() descDesc := sqlbase.WrapDescriptor(dbDesc) b := client.Batch{} b.CPut(newKey, descID, nil) b.Put(descKey, descDesc) b.Del(oldKey) if err := p.txn.Run(&b); err != nil { if _, ok := err.(*roachpb.ConditionFailedError); ok { return nil, fmt.Errorf("the new database name %q already exists", string(n.NewName)) } return nil, err } p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, newKey, descID); err != nil { return err } if err := expectDescriptor(systemConfig, descKey, descDesc); err != nil { return err } return expectDeleted(systemConfig, oldKey) }) return &emptyNode{}, nil }
// Set sets session variables. // Privileges: None. // Notes: postgres/mysql do not require privileges for session variables (some exceptions). func (p *planner) Set(n *parser.Set) (planNode, error) { if n.Name == nil { // A client has sent the reserved internal syntax SET ROW ... // Reject it. return nil, errors.New("invalid statement: SET ROW") } // By using QualifiedName.String() here any variables that are keywords will // be double quoted. name := strings.ToUpper(n.Name.String()) typedValues := make([]parser.TypedExpr, len(n.Values)) for i, expr := range n.Values { typedValue, err := parser.TypeCheck(expr, nil, parser.TypeString) if err != nil { return nil, err } typedValues[i] = typedValue } switch name { case `DATABASE`: dbName, err := p.getStringVal(name, typedValues) if err != nil { return nil, err } if len(dbName) != 0 { // Verify database descriptor exists. dbDesc, err := p.getDatabaseDesc(dbName) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(dbName) } } p.session.Database = dbName case `SYNTAX`: s, err := p.getStringVal(name, typedValues) if err != nil { return nil, err } switch sqlbase.NormalizeName(s) { case sqlbase.NormalizeName(parser.Modern.String()): p.session.Syntax = int32(parser.Modern) case sqlbase.NormalizeName(parser.Traditional.String()): p.session.Syntax = int32(parser.Traditional) default: return nil, fmt.Errorf("%s: \"%s\" is not in (%q, %q)", name, s, parser.Modern, parser.Traditional) } case `EXTRA_FLOAT_DIGITS`: // These settings are sent by the JDBC driver but we silently ignore them. default: return nil, fmt.Errorf("unknown variable: %q", name) } return &emptyNode{}, nil }
// getDatabaseDesc implements the DatabaseAccessor interface. func (p *planner) mustGetDatabaseDesc(name string) (*sqlbase.DatabaseDescriptor, error) { desc, err := p.getDatabaseDesc(name) if err != nil { return nil, err } if desc == nil { return nil, sqlbase.NewUndefinedDatabaseError(name) } return desc, nil }
// getDescriptorsFromTargetList implements the DescriptorAccessor interface. func (p *planner) getDescriptorsFromTargetList(targets parser.TargetList) ( []sqlbase.DescriptorProto, error) { if targets.Databases != nil { if len(targets.Databases) == 0 { return nil, errNoDatabase } descs := make([]sqlbase.DescriptorProto, 0, len(targets.Databases)) for _, database := range targets.Databases { descriptor, err := p.getDatabaseDesc(database) if err != nil { return nil, err } if descriptor == nil { return nil, sqlbase.NewUndefinedDatabaseError(database) } descs = append(descs, descriptor) } return descs, nil } if len(targets.Tables) == 0 { return nil, errNoTable } descs := make([]sqlbase.DescriptorProto, 0, len(targets.Tables)) for _, tableGlob := range targets.Tables { tables, err := p.expandTableGlob(tableGlob) if err != nil { return nil, err } for _, table := range tables { descriptor, err := p.getTableDesc(table) if err != nil { return nil, err } if descriptor == nil { return nil, sqlbase.NewUndefinedTableError(table.String()) } descs = append(descs, descriptor) } } return descs, nil }
// getTableDesc implements the SchemaAccessor interface. func (p *planner) getTableDesc(qname *parser.QualifiedName) (*sqlbase.TableDescriptor, error) { if err := qname.NormalizeTableName(p.session.Database); err != nil { return nil, err } dbDesc, err := p.getDatabaseDesc(qname.Database()) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(qname.Database()) } desc := sqlbase.TableDescriptor{} found, err := p.getDescriptor(tableKey{parentID: dbDesc.ID, name: qname.Table()}, &desc) if err != nil { return nil, err } if !found { return nil, nil } return &desc, nil }
// RenameColumn renames the column. // Privileges: CREATE on table. // notes: postgres requires CREATE on the table. // mysql requires ALTER, CREATE, INSERT on the table. func (p *planner) RenameColumn(n *parser.RenameColumn) (planNode, error) { newColName := string(n.NewName) if newColName == "" { return nil, errEmptyColumnName } if err := n.Table.NormalizeTableName(p.session.Database); err != nil { return nil, err } dbDesc, err := p.getDatabaseDesc(n.Table.Database()) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(n.Table.Database()) } // Check if table exists. tbKey := tableKey{dbDesc.ID, n.Table.Table()}.Key() gr, err := p.txn.Get(tbKey) if err != nil { return nil, err } if !gr.Exists() { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, fmt.Errorf("table %q does not exist", n.Table.Table()) } tableDesc, err := p.getTableDesc(n.Table) if err != nil { return nil, err } if tableDesc == nil { return nil, sqlbase.NewUndefinedTableError(n.Table.String()) } colName := string(n.Name) status, i, err := tableDesc.FindColumnByName(colName) // n.IfExists only applies to table, no need to check here. if err != nil { return nil, err } var column *sqlbase.ColumnDescriptor if status == sqlbase.DescriptorActive { column = &tableDesc.Columns[i] } else { column = tableDesc.Mutations[i].GetColumn() } if err := p.checkPrivilege(tableDesc, privilege.CREATE); err != nil { return nil, err } if sqlbase.EqualName(colName, newColName) { // Noop. return &emptyNode{}, nil } if _, _, err := tableDesc.FindColumnByName(newColName); err == nil { return nil, fmt.Errorf("column name %q already exists", newColName) } preFn := func(expr parser.Expr) (err error, recurse bool, newExpr parser.Expr) { if qname, ok := expr.(*parser.QualifiedName); ok { if err := qname.NormalizeColumnName(); err != nil { return err, false, nil } if qname.Column() == colName { qname.Indirect[0] = parser.NameIndirection(newColName) qname.ClearString() } return nil, false, qname } return nil, true, expr } exprStrings := make([]string, len(tableDesc.Checks)) for i, check := range tableDesc.Checks { exprStrings[i] = check.Expr } exprs, err := parser.ParseExprsTraditional(exprStrings) if err != nil { return nil, err } for i := range tableDesc.Checks { expr, err := parser.SimpleVisit(exprs[i], preFn) if err != nil { return nil, err } if after := expr.String(); after != tableDesc.Checks[i].Expr { tableDesc.Checks[i].Expr = after } } // Rename the column in the indexes. tableDesc.RenameColumn(column.ID, newColName) column.Name = newColName if err := tableDesc.SetUpVersion(); err != nil { return nil, err } descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) if err := tableDesc.Validate(); err != nil { return nil, err } if err := p.txn.Put(descKey, sqlbase.WrapDescriptor(tableDesc)); err != nil { return nil, err } p.notifySchemaChange(tableDesc.ID, sqlbase.InvalidMutationID) return &emptyNode{}, nil }
// RenameTable renames the table. // Privileges: DROP on source table, 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) { if err := n.NewName.NormalizeTableName(p.session.Database); err != nil { return nil, err } if n.NewName.Table() == "" { return nil, errEmptyTableName } if err := n.Name.NormalizeTableName(p.session.Database); err != nil { return nil, err } dbDesc, err := p.getDatabaseDesc(n.Name.Database()) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(n.Name.Database()) } tbKey := tableKey{dbDesc.ID, n.Name.Table()}.Key() // Check if table exists. gr, err := p.txn.Get(tbKey) if err != nil { return nil, err } if !gr.Exists() { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, fmt.Errorf("table %q does not exist", n.Name.Table()) } targetDbDesc, err := p.getDatabaseDesc(n.NewName.Database()) if err != nil { return nil, err } if targetDbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(n.NewName.Database()) } if err := p.checkPrivilege(targetDbDesc, privilege.CREATE); err != nil { return nil, err } if n.Name.Database() == n.NewName.Database() && n.Name.Table() == n.NewName.Table() { // Noop. return &emptyNode{}, nil } tableDesc, err := p.getTableDesc(n.Name) if err != nil { return nil, err } if tableDesc == nil || tableDesc.State != sqlbase.TableDescriptor_PUBLIC { return nil, sqlbase.NewUndefinedTableError(n.Name.String()) } if err := p.checkPrivilege(tableDesc, privilege.DROP); err != nil { return nil, err } tableDesc.SetName(n.NewName.Table()) tableDesc.ParentID = targetDbDesc.ID descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) newTbKey := tableKey{targetDbDesc.ID, n.NewName.Table()}.Key() if err := tableDesc.Validate(); 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: uint32(dbDesc.ID), OldName: n.Name.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, fmt.Errorf("table name %q already exists", n.NewName.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 }
// RenameColumn renames the column. // Privileges: CREATE on table. // notes: postgres requires CREATE on the table. // mysql requires ALTER, CREATE, INSERT on the table. func (p *planner) RenameColumn(n *parser.RenameColumn) (planNode, error) { newColName := string(n.NewName) if newColName == "" { return nil, errEmptyColumnName } if err := n.Table.NormalizeTableName(p.session.Database); err != nil { return nil, err } dbDesc, err := p.getDatabaseDesc(n.Table.Database()) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(n.Table.Database()) } // Check if table exists. tbKey := tableKey{dbDesc.ID, n.Table.Table()}.Key() gr, err := p.txn.Get(tbKey) if err != nil { return nil, err } if !gr.Exists() { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, fmt.Errorf("table %q does not exist", n.Table.Table()) } tableDesc, err := p.getTableDesc(n.Table) if err != nil { return nil, err } if tableDesc == nil { return nil, sqlbase.NewUndefinedTableError(n.Table.String()) } colName := string(n.Name) status, i, err := tableDesc.FindColumnByName(colName) // n.IfExists only applies to table, no need to check here. if err != nil { return nil, err } var column *sqlbase.ColumnDescriptor if status == sqlbase.DescriptorActive { column = &tableDesc.Columns[i] } else { column = tableDesc.Mutations[i].GetColumn() } if err := p.checkPrivilege(tableDesc, privilege.CREATE); err != nil { return nil, err } if sqlbase.EqualName(colName, newColName) { // Noop. return &emptyNode{}, nil } if _, _, err := tableDesc.FindColumnByName(newColName); err == nil { return nil, fmt.Errorf("column name %q already exists", newColName) } // Rename the column in the indexes. tableDesc.RenameColumn(column.ID, newColName) column.Name = newColName if err := tableDesc.SetUpVersion(); err != nil { return nil, err } descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) if err := tableDesc.Validate(); err != nil { return nil, err } if err := p.txn.Put(descKey, sqlbase.WrapDescriptor(tableDesc)); err != nil { return nil, err } p.notifySchemaChange(tableDesc.ID, sqlbase.InvalidMutationID) return &emptyNode{}, nil }