func (s *selectNode) ExplainTypes(regTypes func(string, string)) { if s.filter != nil { regTypes("filter", parser.AsStringWithFlags(s.filter, parser.FmtShowTypes)) } for i, rexpr := range s.render { regTypes(fmt.Sprintf("render %d", i), parser.AsStringWithFlags(rexpr, parser.FmtShowTypes)) } }
func (n *limitNode) ExplainTypes(regTypes func(string, string)) { if n.countExpr != nil { regTypes("count", parser.AsStringWithFlags(n.countExpr, parser.FmtShowTypes)) } if n.offsetExpr != nil { regTypes("offset", parser.AsStringWithFlags(n.offsetExpr, parser.FmtShowTypes)) } }
func (n *insertNode) ExplainTypes(regTypes func(string, string)) { for i, dexpr := range n.defaultExprs { regTypes(fmt.Sprintf("default %d", i), parser.AsStringWithFlags(dexpr, parser.FmtShowTypes)) } for i, cexpr := range n.checkHelper.exprs { regTypes(fmt.Sprintf("check %d", i), parser.AsStringWithFlags(cexpr, parser.FmtShowTypes)) } cols := n.rh.columns for i, rexpr := range n.rh.exprs { regTypes(fmt.Sprintf("returning %s", cols[i].Name), parser.AsStringWithFlags(rexpr, parser.FmtShowTypes)) } }
// explain extract information from planNodes and produces the EXPLAIN // output via the makeRow callback in the explainer. func (e *explainer) explain(plan planNode) { if e.err != nil { return } name, description, children := plan.ExplainPlan(e.showMetadata) if name == "select" && !e.showSelectTop { e.explain(children[len(children)-1]) return } e.node(name, description, plan) if e.showExprs { plan.explainExprs(func(elt string, expr parser.Expr) { if e.err != nil { return } if expr != nil { e.attr(name, elt, parser.AsStringWithFlags(expr, e.fmtFlags)) } }) } for _, child := range children { e.subnode(child) } }
// addOrMergeRenders adds the given result columns to the select // render list and returns their column indices. If an expression is // already rendered, and the reuse flag is true, no new render is // added and the index of the existing column is returned instead. func (s *selectNode) addOrMergeRenders( cols ResultColumns, exprs []parser.TypedExpr, reuseExistingRender bool, ) (colIdxs []int) { colIdxs = make([]int, len(cols)) for i := range cols { index := -1 if reuseExistingRender { // Now, try to find an equivalent render. We use the syntax // representation as approximation of equivalence. At this // point the expressions must have underwent name resolution // already so that comparison occurs after replacing column names // to IndexedVars. exprStr := parser.AsStringWithFlags(exprs[i], parser.FmtSymbolicVars) for j := range s.render { if s.isRenderEquivalent(exprStr, j) { index = j break } } } if index == -1 { index = len(s.render) s.addRenderColumn(exprs[i], cols[i]) } colIdxs[i] = index } return colIdxs }
// expr implements the planObserver interface. func (e *explainer) expr(nodeName, fieldName string, n int, expr parser.Expr) { if e.showExprs && expr != nil { if nodeName == "join" { qualifySave := e.fmtFlags.ShowTableAliases e.fmtFlags.ShowTableAliases = true defer func() { e.fmtFlags.ShowTableAliases = qualifySave }() } if n >= 0 { fieldName = fmt.Sprintf("%s %d", fieldName, n) } e.attr(nodeName, fieldName, parser.AsStringWithFlags(expr, e.fmtFlags)) } }
func (u *updateNode) ExplainTypes(regTypes func(string, string)) { cols := u.rh.columns for i, rexpr := range u.rh.exprs { regTypes(fmt.Sprintf("returning %s", cols[i].Name), parser.AsStringWithFlags(rexpr, parser.FmtShowTypes)) } }
// 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 } // Multiple tests below use selectNode as a special case. // So factor the cast. s, _ := n.(*selectNode) // 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 != nil { numOriginalCols = s.numOriginalCols } var ordering sqlbase.ColumnOrdering for _, o := range orderBy { direction := encoding.Ascending if o.Direction == parser.Descending { direction = encoding.Descending } index := -1 // Unwrap parenthesized expressions like "((a))" to "a". expr := parser.StripParens(o.Expr) // The logical data source for ORDER BY is the list of render // expressions for a SELECT, as specified in the input SQL text // (or an entire UNION or VALUES clause). Alas, SQL has some // historical baggage and there are some special cases: // // 1) column ordinals. If a simple integer literal is used, // optionally enclosed within parentheses but *not subject to // any arithmetic*, then this refers to one of the columns of // the data source. Then use the render expression at that // ordinal position as sort key. // // 2) if the expression is the aliased (AS) name of a render // expression in a SELECT clause, then use that // render as sort key. // e.g. SELECT a AS b, b AS c ORDER BY b // this sorts on the first render. // // 3) otherwise, if the expression is already in the render list, // then use that render as sort key. // e.g. SELECT b AS c ORDER BY b // this sorts on the first render. // (this is an optimization) // // 4) if the sort key is not dependent on the data source (no // IndexedVar) then simply do not sort. (this is an optimization) // // 5) otherwise, add a new render with the ORDER BY expression // and use that as sort key. // e.g. SELECT a FROM t ORDER by b // e.g. SELECT a, b FROM t ORDER by a+b // // So first, deal with column ordinals. col, err := p.colIndex(numOriginalCols, expr, "ORDER BY") if err != nil { return nil, err } if col != -1 { index = col } // Now, deal with render aliases. if vBase, ok := expr.(parser.VarName); index == -1 && ok { v, err := vBase.NormalizeVarName() if err != nil { return nil, err } if c, ok := v.(*parser.ColumnItem); ok && 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 := c.ColumnName.Normalize() for j, col := range columns { if parser.ReNormalizeName(col.Name) == target { index = j break } } } } if s != nil { // Try to optimize constant sorts. For this we need to resolve // names to IndexedVars then see if there were any vars // substituted. sortExpr := expr if index != -1 { // We found a render above, so fetch it. This is needed // because if the sort expression is a reference to a render // alias, resolveNames below would be incorrect. sortExpr = s.render[index] } resolved, hasVars, err := p.resolveNames(sortExpr, s.sourceInfo, s.ivarHelper) if err != nil { return nil, err } if !hasVars { // No sorting needed! continue } // Now, try to find an equivalent render. We use the syntax // representation as approximation of equivalence. // We also use the expression after name resolution so // that comparison occurs after replacing ordinal references // to IndexedVars. if index == -1 { exprStr := parser.AsStringWithFlags(resolved, parser.FmtSymbolicVars) for j, render := range s.render { if parser.AsStringWithFlags(render, parser.FmtSymbolicVars) == exprStr { index = j break } } } } // Finally, if we haven't found anything so far, we really // need a new render. // TODO(knz/dan) currently this is only possible for selectNode. // If we are dealing with a UNION or something else we would need // to fabricate an intermediate selectNode to add the new render. if index == -1 && s != nil { // We need to add a new render, but let's be careful: if there's // a star in there, we're really adding multiple columns. These // all become sort columns! And if no columns are expanded, then // no columns become sort keys. nextRenderIdx := len(s.render) // TODO(knz) the optimizations above which reuse existing // renders and skip ordering for constant expressions are not // applied by addRender(). In other words, "ORDER BY foo.*" will // not be optimized as well as "ORDER BY foo.x, foo.y". We // could do this either here or as a separate later // optimization. if err := s.addRender(parser.SelectExpr{Expr: expr}, nil); err != nil { return nil, err } for extraIdx := nextRenderIdx; extraIdx < len(s.render)-1; extraIdx++ { // If more than 1 column were expanded, turn them into sort columns too. // Except the last one, which will be added below. ordering = append(ordering, sqlbase.ColumnOrderInfo{ColIdx: extraIdx, Direction: direction}) } if len(s.render) == nextRenderIdx { // Nothing was expanded! So there is no order here. continue } index = len(s.render) - 1 } if index == -1 { return nil, errors.Errorf("column %s does not exist", expr) } ordering = append(ordering, sqlbase.ColumnOrderInfo{ColIdx: index, Direction: direction}) } if ordering == nil { // All the sort expressions are constant. Simply drop the sort node. return nil, nil } return &sortNode{ctx: p.ctx(), p: p, columns: columns, ordering: ordering}, nil }
// ExplainTypes implements the planNode interface. func (n *joinNode) ExplainTypes(regTypes func(string, string)) { if n.pred.filter != nil { regTypes("filter", parser.AsStringWithFlags(n.pred.filter, parser.FmtShowTypes)) } }
// TestCopyRandom inserts 100 random rows using COPY and ensures the SELECT'd // data is the same. func TestCopyRandom(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, db, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() if _, err := db.Exec(` CREATE DATABASE d; CREATE TABLE IF NOT EXISTS d.t ( id INT PRIMARY KEY, n INTERVAL, o BOOL, i INT, f FLOAT, e DECIMAL, t TIMESTAMP, s STRING, b BYTES, tz TIMESTAMP WITH TIME ZONE ); `); err != nil { t.Fatal(err) } txn, err := db.Begin() if err != nil { t.Fatal(err) } stmt, err := txn.Prepare(pq.CopyInSchema("d", "t", "id", "n", "o", "i", "f", "e", "t", "s", "b", "tz")) if err != nil { t.Fatal(err) } rng := rand.New(rand.NewSource(0)) types := []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_BOOL, sqlbase.ColumnType_INT, sqlbase.ColumnType_FLOAT, sqlbase.ColumnType_DECIMAL, sqlbase.ColumnType_TIMESTAMP, sqlbase.ColumnType_STRING, sqlbase.ColumnType_BYTES, sqlbase.ColumnType_TIMESTAMPTZ, } var inputs [][]interface{} for i := 0; i < 100; i++ { row := make([]interface{}, len(types)+2) row[0] = strconv.Itoa(i) row[1] = time.Duration(rng.Int63()).String() for j, t := range types { d := sqlbase.RandDatum(rng, sqlbase.ColumnType{Kind: t}, false) ds := parser.AsStringWithFlags(d, parser.FmtBareStrings) switch t { case sqlbase.ColumnType_DECIMAL: // Trailing 0s aren't represented below, so truncate here. ds = strings.TrimRight(ds, "0") } row[j+2] = ds } _, err = stmt.Exec(row...) if err != nil { t.Fatal(err) } inputs = append(inputs, row) } err = stmt.Close() if err != nil { t.Fatal(err) } err = txn.Commit() if err != nil { t.Fatal(err) } rows, err := db.Query("SELECT * FROM d.t ORDER BY id") if err != nil { t.Fatal(err) } for row, in := range inputs { if !rows.Next() { t.Fatal("expected more results") } data := make([]interface{}, len(in)) for i := range data { data[i] = new(interface{}) } if err := rows.Scan(data...); err != nil { t.Fatal(err) } for i, d := range data { v := d.(*interface{}) d := *v ds := fmt.Sprint(d) switch d := d.(type) { case []byte: ds = string(d) case time.Time: dt := parser.MakeDTimestamp(d, time.Microsecond) ds = parser.AsStringWithFlags(dt, parser.FmtBareStrings) } if !reflect.DeepEqual(in[i], ds) { t.Fatalf("row %v, col %v: got %#v (%T), expected %#v", row, i, ds, d, in[i]) } } } }
// isRenderEquivalent is a helper function for equivalentRenders() and // addOrMergeRenders(). Do not use directly. func (s *selectNode) isRenderEquivalent(exprStr string, j int) bool { return parser.AsStringWithFlags(s.render[j], parser.FmtSymbolicVars) == exprStr }
// equivalentRenders returns true if and only if the two render expressions // are equivalent. func (s *selectNode) equivalentRenders(i, j int) bool { firstExprStr := parser.AsStringWithFlags(s.render[i], parser.FmtSymbolicVars) return s.isRenderEquivalent(firstExprStr, j) }