func (p *planner) getTableNames(dbDesc *DatabaseDescriptor) (parser.QualifiedNames, *roachpb.Error) { prefix := MakeNameMetadataKey(dbDesc.ID, "") sr, pErr := p.txn.Scan(prefix, prefix.PrefixEnd(), 0) if pErr != nil { return nil, pErr } var qualifiedNames parser.QualifiedNames for _, row := range sr { _, tableName, err := encoding.DecodeStringAscending( bytes.TrimPrefix(row.Key, prefix), nil) if err != nil { return nil, roachpb.NewError(err) } qname := &parser.QualifiedName{ Base: parser.Name(dbDesc.Name), Indirect: parser.Indirection{parser.NameIndirection(tableName)}, } if err := qname.NormalizeTableName(""); err != nil { return nil, roachpb.NewError(err) } qualifiedNames = append(qualifiedNames, qname) } return qualifiedNames, nil }
// upsertExprsAndIndex returns the upsert conflict index and the (possibly // synthetic) SET expressions used when a row conflicts. func upsertExprsAndIndex( tableDesc *sqlbase.TableDescriptor, onConflict parser.OnConflict, insertCols []sqlbase.ColumnDescriptor, ) (parser.UpdateExprs, *sqlbase.IndexDescriptor, error) { if onConflict.IsUpsertAlias() { // The UPSERT syntactic sugar is the same as the longhand specifying the // primary index as the conflict index and SET expressions for the columns // in insertCols minus any columns in the conflict index. Example: // `UPSERT INTO abc VALUES (1, 2, 3)` is syntactic sugar for // `INSERT INTO abc VALUES (1, 2, 3) ON CONFLICT a DO UPDATE SET b = 2, c = 3`. conflictIndex := &tableDesc.PrimaryIndex indexColSet := make(map[sqlbase.ColumnID]struct{}, len(conflictIndex.ColumnIDs)) for _, colID := range conflictIndex.ColumnIDs { indexColSet[colID] = struct{}{} } updateExprs := make(parser.UpdateExprs, 0, len(insertCols)) for _, c := range insertCols { if _, ok := indexColSet[c.ID]; !ok { names := parser.QualifiedNames{&parser.QualifiedName{Base: parser.Name(c.Name)}} expr := &parser.QualifiedName{ Base: upsertExcludedTable, Indirect: parser.Indirection{parser.NameIndirection(c.Name)}, } if err := expr.NormalizeColumnName(); err != nil { return nil, nil, err } updateExprs = append(updateExprs, &parser.UpdateExpr{Names: names, Expr: expr}) } } return updateExprs, conflictIndex, nil } indexMatch := func(index sqlbase.IndexDescriptor) bool { if !index.Unique { return false } if len(index.ColumnNames) != len(onConflict.Columns) { return false } for i, colName := range index.ColumnNames { if colName != onConflict.Columns[i] { return false } } return true } if indexMatch(tableDesc.PrimaryIndex) { return onConflict.Exprs, &tableDesc.PrimaryIndex, nil } for _, index := range tableDesc.Indexes { if indexMatch(index) { return onConflict.Exprs, &index, nil } } return nil, nil, fmt.Errorf("there is no unique or exclusion constraint matching the ON CONFLICT specification") }
func (p *planner) normalizeTableName(qname *parser.QualifiedName) error { if qname == nil || qname.Base == "" { return fmt.Errorf("empty table name: %s", qname) } if len(qname.Indirect) == 0 { if p.session.Database == "" { return fmt.Errorf("no database specified") } qname.Indirect = append(qname.Indirect, parser.NameIndirection(qname.Base)) qname.Base = parser.Name(p.session.Database) } return nil }
func (p *planner) getTableNames(dbDesc *structured.DatabaseDescriptor) (parser.QualifiedNames, error) { prefix := structured.MakeNameMetadataKey(dbDesc.ID, "") sr, err := p.db.Scan(prefix, prefix.PrefixEnd(), 0) if err != nil { return nil, err } var qualifiedNames parser.QualifiedNames for _, row := range sr { tableName := string(bytes.TrimPrefix(row.Key, prefix)) qualifiedNames = append(qualifiedNames, &parser.QualifiedName{ Base: parser.Name(dbDesc.Name), Indirect: parser.Indirection{parser.NameIndirection(tableName)}, }) } return qualifiedNames, 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 }