// 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 VarName.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. if _, err := p.mustGetDatabaseDesc(dbName); err != nil { return nil, err } } p.session.Database = dbName case `SYNTAX`: s, err := p.getStringVal(name, typedValues) if err != nil { return nil, err } switch sqlbase.NormalizeName(parser.Name(s)) { case sqlbase.ReNormalizeName(parser.Modern.String()): p.session.Syntax = int32(parser.Modern) case sqlbase.ReNormalizeName(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 }
// 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.UnresolvedNames{ parser.UnresolvedName{parser.Name(c.Name)}, } expr := &parser.ColumnItem{ TableName: upsertExcludedTable, ColumnName: parser.Name(c.Name), } 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 sqlbase.ReNormalizeName(colName) != sqlbase.NormalizeName(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") }
// Initializes a scanNode with a tableName. Returns the table or index name that can be used for // fully-qualified columns if an alias is not specified. func (n *scanNode) initTable( p *planner, tableName *parser.TableName, indexHints *parser.IndexHints, scanVisibility scanVisibility, ) error { descFunc := p.getTableLease if p.asOf { // AS OF SYSTEM TIME queries need to fetch the table descriptor at the // specified time, and never lease anything. The proto transaction already // has its timestamps set correctly so mustGetTableDesc will fetch with the // correct timestamp. descFunc = p.mustGetTableDesc } desc, err := descFunc(tableName) if err != nil { return err } n.desc = *desc if err := p.checkPrivilege(&n.desc, privilege.SELECT); err != nil { return err } if indexHints != nil && indexHints.Index != "" { indexName := sqlbase.NormalizeName(indexHints.Index) if indexName == sqlbase.ReNormalizeName(n.desc.PrimaryIndex.Name) { n.specifiedIndex = &n.desc.PrimaryIndex } else { for i := range n.desc.Indexes { if indexName == sqlbase.ReNormalizeName(n.desc.Indexes[i].Name) { n.specifiedIndex = &n.desc.Indexes[i] break } } if n.specifiedIndex == nil { return fmt.Errorf("index \"%s\" not found", indexName) } } } n.noIndexJoin = (indexHints != nil && indexHints.NoIndexJoin) n.initDescDefaults(scanVisibility) return nil }
// findUnaliasedColumn looks up the column specified by a VarName, not // taking column renames into account (but table renames will be taken // into account). That is, given a table "blah" with single column "y", // findUnaliasedColumn("y") returns a valid index even in the context // of: // SELECT * FROM blah as foo(x) // If the VarName specifies a table name, only columns that have that // name as their source alias are considered. If the VarName does not // specify a table name, all columns in the data source are // considered. If no column is found, invalidColIdx is returned with // no error. func (p *planDataSource) findUnaliasedColumn( c *parser.ColumnItem, ) (colIdx int, err error) { colName := sqlbase.NormalizeName(c.ColumnName) tableName := sqlbase.NormalizeTableName(c.TableName) if tableName.Table() != "" { tn, err := p.info.checkDatabaseName(tableName) if err != nil { return invalidColIdx, nil } tableName = tn } colIdx = invalidColIdx planColumns := p.plan.Columns() selCol := func(colIdx int, idx int) (int, error) { col := planColumns[idx] if sqlbase.ReNormalizeName(col.Name) == colName { if colIdx != invalidColIdx { return invalidColIdx, fmt.Errorf("column reference \"%s\" is ambiguous", parser.AsString(c)) } colIdx = idx } return colIdx, nil } if tableName.Table() == "" { for idx := 0; idx < len(p.info.sourceColumns); idx++ { colIdx, err = selCol(colIdx, idx) if err != nil { return colIdx, err } } } else { colRange, ok := p.info.sourceAliases[tableName] if !ok { // A table name is specified, but there is no column with this // table name. return invalidColIdx, nil } for _, idx := range colRange { colIdx, err = selCol(colIdx, idx) if err != nil { return colIdx, err } } } return colIdx, nil }
func makeColIDtoRowIndex(row planNode, desc *sqlbase.TableDescriptor) ( map[sqlbase.ColumnID]int, error, ) { columns := row.Columns() colIDtoRowIndex := make(map[sqlbase.ColumnID]int, len(columns)) for i, column := range columns { s, idx, err := desc.FindColumnByNormalizedName(sqlbase.ReNormalizeName(column.Name)) if err != nil { return nil, err } switch s { case sqlbase.DescriptorActive: colIDtoRowIndex[desc.Columns[idx].ID] = i case sqlbase.DescriptorIncomplete: colIDtoRowIndex[desc.Mutations[idx].GetColumn().ID] = i default: panic("unreachable") } } return colIDtoRowIndex, nil }
func nameMatchesLease(lease *LeaseState, dbID sqlbase.ID, tableName string) bool { return lease.ParentID == dbID && sqlbase.ReNormalizeName(lease.Name) == sqlbase.ReNormalizeName(tableName) }
func makeTableNameCacheKey(dbID sqlbase.ID, tableName string) tableNameCacheKey { return tableNameCacheKey{dbID, sqlbase.ReNormalizeName(tableName)} }
// findColumn looks up the column specified by a VarName. The normalized VarName // is returned. func (sources multiSourceInfo) findColumn( c *parser.ColumnItem, ) (info *dataSourceInfo, colIdx int, err error) { if len(c.Selector) > 0 { return nil, invalidColIdx, util.UnimplementedWithIssueErrorf(8318, "compound types not supported yet: %q", c) } colName := sqlbase.NormalizeName(c.ColumnName) var tableName parser.TableName if c.TableName.Table() != "" { tableName = sqlbase.NormalizeTableName(c.TableName) tn, err := sources.checkDatabaseName(tableName) if err != nil { return nil, invalidColIdx, err } tableName = tn // Propagate the discovered database name back to the original VarName. // (to clarify the output of e.g. EXPLAIN) c.TableName.DatabaseName = tableName.DatabaseName } colIdx = invalidColIdx for _, src := range sources { findCol := func(src, info *dataSourceInfo, colIdx int, idx int) (*dataSourceInfo, int, error) { col := src.sourceColumns[idx] if sqlbase.ReNormalizeName(col.Name) == colName { if colIdx != invalidColIdx { return nil, invalidColIdx, fmt.Errorf("column reference %q is ambiguous", c) } info = src colIdx = idx } return info, colIdx, nil } if tableName.Table() == "" { for idx := 0; idx < len(src.sourceColumns); idx++ { info, colIdx, err = findCol(src, info, colIdx, idx) if err != nil { return info, colIdx, err } } } else { colRange, ok := src.sourceAliases[tableName] if !ok { // The data source "src" has no column for table tableName. // Try again with the net one. continue } for _, idx := range colRange { info, colIdx, err = findCol(src, info, colIdx, idx) if err != nil { return info, colIdx, err } } } } if colIdx == invalidColIdx { return nil, invalidColIdx, fmt.Errorf("column name %q not found", c) } return info, colIdx, nil }
// orderBy constructs a sortNode based on the ORDER BY clause. // // In the general case (SELECT/UNION/VALUES), we can sort by a column index or a // column name. // // However, for a SELECT, we can also sort by the pre-alias column name (SELECT // a AS b ORDER BY b) as well as expressions (SELECT a, b, ORDER BY a+b). In // this case, construction of the sortNode might adjust the number of render // targets in the selectNode if any ordering expressions are specified. // // TODO(dan): SQL also allows sorting a VALUES or UNION by an expression. // Support this. It will reduce some of the special casing below, but requires a // generalization of how to add derived columns to a SelectStatement. func (p *planner) orderBy(orderBy parser.OrderBy, n planNode) (*sortNode, error) { if orderBy == nil { return nil, nil } // We grab a copy of columns here because we might add new render targets // below. This is the set of columns requested by the query. columns := n.Columns() numOriginalCols := len(columns) if s, ok := n.(*selectNode); ok { numOriginalCols = s.numOriginalCols } var ordering sqlbase.ColumnOrdering for _, o := range orderBy { index := -1 // Unwrap parenthesized expressions like "((a))" to "a". expr := parser.StripParens(o.Expr) if vBase, ok := expr.(parser.VarName); ok { v, err := vBase.NormalizeVarName() if err != nil { return nil, err } var c *parser.ColumnItem switch t := v.(type) { case *parser.ColumnItem: c = t default: return nil, fmt.Errorf("invalid syntax for ORDER BY: %s", v) } if c.TableName.Table() == "" { // Look for an output column that matches the name. This // handles cases like: // // SELECT a AS b FROM t ORDER BY b target := sqlbase.NormalizeName(c.ColumnName) for j, col := range columns { if sqlbase.ReNormalizeName(col.Name) == target { index = j break } } } if s, ok := n.(*selectNode); ok && index == -1 { // No output column matched the name, so look for an existing // render target that matches the column name. This handles cases like: // // SELECT a AS b FROM t ORDER BY a colIdx, err := s.source.findUnaliasedColumn(c) if err != nil { return nil, err } if colIdx != invalidColIdx { for j, r := range s.render { if qval, ok := r.(*qvalue); ok { if qval.colRef.source == s.source.info && qval.colRef.colIdx == colIdx { index = j break } } } } } } if index == -1 { // The order by expression matched neither an output column nor an // existing render target. if col, err := colIndex(numOriginalCols, expr); err != nil { return nil, err } else if col >= 0 { index = col } else if s, ok := n.(*selectNode); ok { // TODO(dan): Once we support VALUES (1), (2) ORDER BY 3*4, this type // check goes away. // Add a new render expression to use for ordering. This // handles cases were the expression is either not a name or // is a name that is otherwise not referenced by the query: // // SELECT a FROM t ORDER by b // SELECT a, b FROM t ORDER by a+b if err := s.addRender(parser.SelectExpr{Expr: expr}, nil); err != nil { return nil, err } index = len(s.columns) - 1 } else { return nil, errors.Errorf("column %s does not exist", expr) } } direction := encoding.Ascending if o.Direction == parser.Descending { direction = encoding.Descending } ordering = append(ordering, sqlbase.ColumnOrderInfo{ColIdx: index, Direction: direction}) } return &sortNode{ctx: p.ctx(), columns: columns, ordering: ordering}, nil }
// getTableLease implements the SchemaAccessor interface. func (p *planner) getTableLease(tn *parser.TableName) (*sqlbase.TableDescriptor, error) { if log.V(2) { log.Infof(p.ctx(), "planner acquiring lease on table %s", tn) } isSystemDB := tn.Database() == sqlbase.SystemDB.Name isVirtualDB := isVirtualDatabase(tn.Database()) if isSystemDB || isVirtualDB || testDisableTableLeases { // We don't go through the normal lease mechanism for: // - system tables. The system.lease and system.descriptor table, in // particular, are problematic because they are used for acquiring // leases itself, creating a chicken&egg problem. // - virtual tables. These tables' descriptors are not persisted, // so they cannot be leased. Instead, we simply return the static // descriptor and rely on the immutability privileges set on the // descriptors to cause upper layers to reject mutations statements. tbl, err := p.mustGetTableDesc(tn) if err != nil { return nil, err } if err := filterTableState(tbl); err != nil { return nil, err } return tbl, nil } dbID, err := p.getDatabaseID(tn.Database()) if err != nil { return nil, err } // First, look to see if we already have a lease for this table. // This ensures that, once a SQL transaction resolved name N to id X, it will // continue to use N to refer to X even if N is renamed during the // transaction. var lease *LeaseState for _, l := range p.leases { if sqlbase.ReNormalizeName(l.Name) == sqlbase.NormalizeName(tn.TableName) && l.ParentID == dbID { lease = l if log.V(2) { log.Infof(p.ctx(), "found lease in planner cache for table %q", tn) } break } } // If we didn't find a lease or the lease is about to expire, acquire one. if lease == nil || p.removeLeaseIfExpiring(lease) { var err error lease, err = p.leaseMgr.AcquireByName(p.txn, dbID, tn.Table()) if err != nil { if err == sqlbase.ErrDescriptorNotFound { // Transform the descriptor error into an error that references the // table's name. return nil, sqlbase.NewUndefinedTableError(tn.String()) } return nil, err } p.leases = append(p.leases, lease) // If the lease we just acquired expires before the txn's deadline, reduce // the deadline. p.txn.UpdateDeadlineMaybe(hlc.Timestamp{WallTime: lease.Expiration().UnixNano()}) } return &lease.TableDescriptor, nil }
func (p *planner) makeUpsertHelper( tn *parser.TableName, tableDesc *sqlbase.TableDescriptor, insertCols []sqlbase.ColumnDescriptor, updateCols []sqlbase.ColumnDescriptor, updateExprs parser.UpdateExprs, upsertConflictIndex *sqlbase.IndexDescriptor, ) (*upsertHelper, error) { defaultExprs, err := makeDefaultExprs(updateCols, &p.parser, &p.evalCtx) if err != nil { return nil, err } untupledExprs := make(parser.Exprs, 0, len(updateExprs)) i := 0 for _, updateExpr := range updateExprs { if updateExpr.Tuple { if t, ok := updateExpr.Expr.(*parser.Tuple); ok { for _, e := range t.Exprs { typ := updateCols[i].Type.ToDatumType() e := fillDefault(e, typ, i, defaultExprs) untupledExprs = append(untupledExprs, e) i++ } } } else { typ := updateCols[i].Type.ToDatumType() e := fillDefault(updateExpr.Expr, typ, i, defaultExprs) untupledExprs = append(untupledExprs, e) i++ } } sourceInfo := newSourceInfoForSingleTable(*tn, makeResultColumns(tableDesc.Columns)) excludedSourceInfo := newSourceInfoForSingleTable(upsertExcludedTable, makeResultColumns(insertCols)) var evalExprs []parser.TypedExpr qvals := make(qvalMap) sources := multiSourceInfo{sourceInfo, excludedSourceInfo} for _, expr := range untupledExprs { normExpr, err := p.analyzeExpr(expr, sources, qvals, parser.NoTypePreference, false, "") if err != nil { return nil, err } evalExprs = append(evalExprs, normExpr) } allExprsIdentity := true for i, expr := range evalExprs { // analyzeExpr above has normalized all direct column names to ColumnItems. c, ok := expr.(*parser.ColumnItem) if !ok { allExprsIdentity = false break } if len(c.Selector) > 0 || !sqlbase.EqualName(c.TableName.TableName, upsertExcludedTable.TableName) || sqlbase.NormalizeName(c.ColumnName) != sqlbase.ReNormalizeName(updateCols[i].Name) { allExprsIdentity = false break } } helper := &upsertHelper{ p: p, qvals: qvals, evalExprs: evalExprs, sourceInfo: sourceInfo, excludedSourceInfo: excludedSourceInfo, allExprsIdentity: allExprsIdentity, } return helper, nil }