func simplifyNotExpr(n *parser.NotExpr) (parser.TypedExpr, bool) { switch t := n.Expr.(type) { case *parser.ComparisonExpr: op := t.Operator switch op { case parser.EQ: op = parser.NE case parser.NE: op = parser.EQ case parser.GT: op = parser.LE case parser.GE: op = parser.LT case parser.LT: op = parser.GE case parser.LE: op = parser.GT case parser.In: op = parser.NotIn case parser.NotIn: op = parser.In case parser.Like: op = parser.NotLike case parser.NotLike: op = parser.Like case parser.SimilarTo: op = parser.NotSimilarTo case parser.NotSimilarTo: op = parser.SimilarTo default: return parser.MakeDBool(true), false } return simplifyExpr(parser.NewTypedComparisonExpr( op, t.TypedLeft(), t.TypedRight(), )) case *parser.AndExpr: // De Morgan's Law: NOT (a AND b) -> (NOT a) OR (NOT b) return simplifyExpr(parser.NewTypedOrExpr( parser.NewTypedNotExpr(t.TypedLeft()), parser.NewTypedNotExpr(t.TypedRight()), )) case *parser.OrExpr: // De Morgan's Law: NOT (a OR b) -> (NOT a) AND (NOT b) return simplifyExpr(parser.NewTypedAndExpr( parser.NewTypedNotExpr(t.TypedLeft()), parser.NewTypedNotExpr(t.TypedRight()), )) } return parser.MakeDBool(true), false }
// ShowIndex returns all the indexes for a table. // Privileges: Any privilege on table. // Notes: postgres does not have a SHOW INDEXES statement. // mysql requires some privilege for any column. func (p *planner) ShowIndex(n *parser.ShowIndex) (planNode, error) { tn, err := n.Table.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } desc, err := p.mustGetTableDesc(tn) if err != nil { return nil, err } if err := p.anyPrivilege(desc); err != nil { return nil, err } v := &valuesNode{ columns: []ResultColumn{ {Name: "Table", Typ: parser.TypeString}, {Name: "Name", Typ: parser.TypeString}, {Name: "Unique", Typ: parser.TypeBool}, {Name: "Seq", Typ: parser.TypeInt}, {Name: "Column", Typ: parser.TypeString}, {Name: "Direction", Typ: parser.TypeString}, {Name: "Storing", Typ: parser.TypeBool}, }, } appendRow := func(index sqlbase.IndexDescriptor, colName string, sequence int, direction string, isStored bool) { v.rows = append(v.rows, []parser.Datum{ parser.NewDString(tn.Table()), parser.NewDString(index.Name), parser.MakeDBool(parser.DBool(index.Unique)), parser.NewDInt(parser.DInt(sequence)), parser.NewDString(colName), parser.NewDString(direction), parser.MakeDBool(parser.DBool(isStored)), }) } for _, index := range append([]sqlbase.IndexDescriptor{desc.PrimaryIndex}, desc.Indexes...) { sequence := 1 for i, col := range index.ColumnNames { appendRow(index, col, sequence, index.ColumnDirections[i].String(), false) sequence++ } for _, col := range index.StoreColumnNames { appendRow(index, col, sequence, "N/A", true) sequence++ } } return v, nil }
// ShowColumns of a table. // Privileges: None. // Notes: postgres does not have a SHOW COLUMNS statement. // mysql only returns columns you have privileges on. func (p *planner) ShowColumns(n *parser.ShowColumns) (planNode, error) { desc, err := p.getTableDesc(n.Table) if err != nil { return nil, err } if desc == nil { return nil, sqlbase.NewUndefinedTableError(n.Table.String()) } v := &valuesNode{ columns: []ResultColumn{ {Name: "Field", Typ: parser.TypeString}, {Name: "Type", Typ: parser.TypeString}, {Name: "Null", Typ: parser.TypeBool}, {Name: "Default", Typ: parser.TypeString}, }, } for i, col := range desc.Columns { defaultExpr := parser.Datum(parser.DNull) if e := desc.Columns[i].DefaultExpr; e != nil { defaultExpr = parser.NewDString(*e) } v.rows = append(v.rows, []parser.Datum{ parser.NewDString(desc.Columns[i].Name), parser.NewDString(col.Type.SQLString()), parser.MakeDBool(parser.DBool(desc.Columns[i].Nullable)), defaultExpr, }) } return v, nil }
// DecodeTableValue decodes a value encoded by EncodeTableValue. func DecodeTableValue(a *DatumAlloc, valType parser.Datum, b []byte) (parser.Datum, []byte, error) { // TODO(dan): Merge this and DecodeTableKey. if len(b) == 0 { return nil, nil, util.Errorf("empty slice") } if roachpb.ValueType(b[0]) == roachpb.ValueType_NULL { return parser.DNull, b[1:], nil } var err error switch valType.(type) { case *parser.DBool: var i int64 b, i, err = roachpb.DecodeIntValue(b) // No need to chunk allocate DBool as MakeDBool returns either // parser.DBoolTrue or parser.DBoolFalse. return parser.MakeDBool(parser.DBool(i != 0)), b, err case *parser.DInt: var i int64 b, i, err = roachpb.DecodeIntValue(b) return a.NewDInt(parser.DInt(i)), b, err case *parser.DFloat: var f float64 b, f, err = roachpb.DecodeFloatValue(b) return a.NewDFloat(parser.DFloat(f)), b, err case *parser.DDecimal: var d *inf.Dec b, d, err = roachpb.DecodeDecimalValue(b) dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(d) return dd, b, err case *parser.DString: var data []byte b, data, err = roachpb.DecodeBytesValue(b) return a.NewDString(parser.DString(data)), b, err case *parser.DBytes: var data []byte b, data, err = roachpb.DecodeBytesValue(b) return a.NewDBytes(parser.DBytes(data)), b, err case *parser.DDate: var i int64 b, i, err = roachpb.DecodeIntValue(b) return a.NewDDate(parser.DDate(i)), b, err case *parser.DTimestamp: var t time.Time b, t, err = roachpb.DecodeTimeValue(b) return a.NewDTimestamp(parser.DTimestamp{Time: t}), b, err case *parser.DTimestampTZ: var t time.Time b, t, err = roachpb.DecodeTimeValue(b) return a.NewDTimestampTZ(parser.DTimestampTZ{Time: t}), b, err case *parser.DInterval: var d duration.Duration b, d, err = roachpb.DecodeDurationValue(b) return a.NewDInterval(parser.DInterval{Duration: d}), b, err default: return nil, nil, util.Errorf("TODO(pmattis): decoded index value: %s", valType.Type()) } }
// DecodeTableValue decodes a value encoded by EncodeTableValue. func DecodeTableValue(a *DatumAlloc, valType parser.Datum, b []byte) (parser.Datum, []byte, error) { _, dataOffset, _, typ, err := encoding.DecodeValueTag(b) if err != nil { return nil, b, err } if typ == encoding.Null { return parser.DNull, b[dataOffset:], nil } switch valType.(type) { case *parser.DBool: var x bool b, x, err = encoding.DecodeBoolValue(b) // No need to chunk allocate DBool as MakeDBool returns either // parser.DBoolTrue or parser.DBoolFalse. return parser.MakeDBool(parser.DBool(x)), b, err case *parser.DInt: var i int64 b, i, err = encoding.DecodeIntValue(b) return a.NewDInt(parser.DInt(i)), b, err case *parser.DFloat: var f float64 b, f, err = encoding.DecodeFloatValue(b) return a.NewDFloat(parser.DFloat(f)), b, err case *parser.DDecimal: var d *inf.Dec b, d, err = encoding.DecodeDecimalValue(b) dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(d) return dd, b, err case *parser.DString: var data []byte b, data, err = encoding.DecodeBytesValue(b) return a.NewDString(parser.DString(data)), b, err case *parser.DBytes: var data []byte b, data, err = encoding.DecodeBytesValue(b) return a.NewDBytes(parser.DBytes(data)), b, err case *parser.DDate: var i int64 b, i, err = encoding.DecodeIntValue(b) return a.NewDDate(parser.DDate(i)), b, err case *parser.DTimestamp: var t time.Time b, t, err = encoding.DecodeTimeValue(b) return a.NewDTimestamp(parser.DTimestamp{Time: t}), b, err case *parser.DTimestampTZ: var t time.Time b, t, err = encoding.DecodeTimeValue(b) return a.NewDTimestampTZ(parser.DTimestampTZ{Time: t}), b, err case *parser.DInterval: var d duration.Duration b, d, err = encoding.DecodeDurationValue(b) return a.NewDInterval(parser.DInterval{Duration: d}), b, err default: return nil, nil, errors.Errorf("TODO(pmattis): decoded index value: %s", valType.Type()) } }
// golangFillQueryArguments populates the placeholder map with // types and values from an array of Go values. // TODO: This does not support arguments of the SQL 'Date' type, as there is not // an equivalent type in Go's standard library. It's not currently needed by any // of our internal tables. func golangFillQueryArguments(pinfo *parser.PlaceholderInfo, args []interface{}) { pinfo.Clear() for i, arg := range args { k := fmt.Sprint(i + 1) if arg == nil { pinfo.SetValue(k, parser.DNull) continue } // A type switch to handle a few explicit types with special semantics: // - Datums are passed along as is. // - Time datatypes get special representation in the database. var d parser.Datum switch t := arg.(type) { case parser.Datum: d = t case time.Time: d = parser.MakeDTimestamp(t, time.Microsecond) case time.Duration: d = &parser.DInterval{Duration: duration.Duration{Nanos: t.Nanoseconds()}} case *inf.Dec: dd := &parser.DDecimal{} dd.Set(t) d = dd } if d == nil { // Handle all types which have an underlying type that can be stored in the // database. // Note: if this reflection becomes a performance concern in the future, // commonly used types could be added explicitly into the type switch above // for a performance gain. val := reflect.ValueOf(arg) switch val.Kind() { case reflect.Bool: d = parser.MakeDBool(parser.DBool(val.Bool())) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: d = parser.NewDInt(parser.DInt(val.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: d = parser.NewDInt(parser.DInt(val.Uint())) case reflect.Float32, reflect.Float64: d = parser.NewDFloat(parser.DFloat(val.Float())) case reflect.String: d = parser.NewDString(val.String()) case reflect.Slice: // Handle byte slices. if val.Type().Elem().Kind() == reflect.Uint8 { d = parser.NewDBytes(parser.DBytes(val.Bytes())) } } if d == nil { panic(fmt.Sprintf("unexpected type %T", arg)) } } pinfo.SetValue(k, d) } }
// Arg implements the parser.Args interface. // TODO: This does not support arguments of the SQL 'Date' type, as there is not // an equivalent type in Go's standard library. It's not currently needed by any // of our internal tables. func (gp golangParameters) Arg(name string) (parser.Datum, bool) { i, err := processPositionalArgument(name) if err != nil { return nil, false } if i < 1 || int(i) > len(gp) { return nil, false } arg := gp[i-1] if arg == nil { return parser.DNull, true } // A type switch to handle a few explicit types with special semantics. switch t := arg.(type) { // Datums are passed along as is. case parser.Datum: return t, true // Time datatypes get special representation in the database. case time.Time: return parser.MakeDTimestamp(t, time.Microsecond), true case time.Duration: return &parser.DInterval{Duration: duration.Duration{Nanos: t.Nanoseconds()}}, true case *inf.Dec: dd := &parser.DDecimal{} dd.Set(t) return dd, true } // Handle all types which have an underlying type that can be stored in the // database. // Note: if this reflection becomes a performance concern in the future, // commonly used types could be added explicitly into the type switch above // for a performance gain. val := reflect.ValueOf(arg) switch val.Kind() { case reflect.Bool: return parser.MakeDBool(parser.DBool(val.Bool())), true case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return parser.NewDInt(parser.DInt(val.Int())), true case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return parser.NewDInt(parser.DInt(val.Uint())), true case reflect.Float32, reflect.Float64: return parser.NewDFloat(parser.DFloat(val.Float())), true case reflect.String: return parser.NewDString(val.String()), true case reflect.Slice: // Handle byte slices. if val.Type().Elem().Kind() == reflect.Uint8 { return parser.NewDBytes(parser.DBytes(val.Bytes())), true } } panic(fmt.Sprintf("unexpected type %T", arg)) }
func simplifyAndExpr(n *parser.AndExpr) (parser.TypedExpr, bool) { // a AND b AND c AND d -> [a, b, c, d] equivalent := true exprs := splitAndExpr(n, nil) for i := range exprs { var equiv bool exprs[i], equiv = simplifyExpr(exprs[i]) if !equiv { equivalent = false } if isKnownFalseOrNull(exprs[i]) { return parser.MakeDBool(false), equivalent } } // Simplifying exprs might have transformed one of the elements into an AND // expression. texprs, exprs := exprs, nil for _, e := range texprs { exprs = splitAndExpr(e, exprs) } // Loop over the expressions looking for simplifications. // // TODO(pmattis): This is O(n^2) in the number of expressions. Could be // optimized by sorting the expressions based on the variables they contain. outer: for i := len(exprs) - 1; i >= 0; i-- { for j := i - 1; j >= 0; j-- { var equiv bool exprs[j], exprs[i], equiv = simplifyOneAndExpr(exprs[j], exprs[i]) if !equiv { equivalent = false } if isKnownFalseOrNull(exprs[j]) { return exprs[j], equivalent } if isKnownTrue(exprs[i]) { exprs[i] = nil } if exprs[i] == nil { // We found a simplification. Strip off the expression that is now nil // and continue the outer loop. n := len(exprs) - 1 exprs[i] = exprs[n] exprs = exprs[:n] continue outer } } } // Reform the AND expressions. return joinAndExprs(exprs), equivalent }
// simplifyExpr transforms an expression such that it contains only expressions // involving qvalues that can be used for index selection. If an expression is // encountered that cannot be used for index selection (e.g. "func(val)") that // part of the expression tree is considered to evaluate to true, possibly // rendering the entire expression as true. Additionally, various // normalizations are performed on comparison expressions. For example: // // (a < 1 AND a < 2) -> (a < 1) // (a < 1 AND a > 2) -> false // (a > 1 OR a < 2) -> true // (a > 1 OR func(b)) -> true // // Note that simplification is not normalization. Normalization as performed by // parser.NormalizeExpr returns an expression that is equivalent to the // original. Simplification can return an expression with parts of the // expression tree stripped out. // // Returns false for equivalent if the resulting expression is not equivalent // to the original. This occurs for expressions which are currently not handled // by simplification. func simplifyExpr(e parser.TypedExpr) (simplified parser.TypedExpr, equivalent bool) { switch t := e.(type) { case *parser.NotExpr: return simplifyNotExpr(t) case *parser.AndExpr: return simplifyAndExpr(t) case *parser.OrExpr: return simplifyOrExpr(t) case *parser.ComparisonExpr: return simplifyComparisonExpr(t) case *qvalue, *parser.IndexedVar, *parser.DBool: return e, true } // We don't know how to simplify expressions that fall through to here, so // consider this part of the expression true. return parser.MakeDBool(true), false }
// RandDatum generates a random Datum of the given type. // If null is true, the datum can be DNull. func RandDatum(rng *rand.Rand, typ ColumnType_Kind, null bool) parser.Datum { if null && rng.Intn(10) == 0 { return parser.DNull } switch typ { case ColumnType_BOOL: return parser.MakeDBool(rng.Intn(2) == 1) case ColumnType_INT: return parser.NewDInt(parser.DInt(rng.Int63())) case ColumnType_FLOAT: return parser.NewDFloat(parser.DFloat(rng.NormFloat64())) case ColumnType_DECIMAL: d := &parser.DDecimal{} d.Dec.SetScale(inf.Scale(rng.Intn(40) - 20)) d.Dec.SetUnscaled(rng.Int63()) return d case ColumnType_DATE: return parser.NewDDate(parser.DDate(rng.Intn(10000))) case ColumnType_TIMESTAMP: return &parser.DTimestamp{Time: time.Unix(rng.Int63n(1000000), rng.Int63n(1000000))} case ColumnType_INTERVAL: return &parser.DInterval{Duration: duration.Duration{Months: rng.Int63n(1000), Days: rng.Int63n(1000), Nanos: rng.Int63n(1000000), }} case ColumnType_STRING: // Generate a random ASCII string. p := make([]byte, rng.Intn(10)) for i := range p { p[i] = byte(1 + rng.Intn(127)) } return parser.NewDString(string(p)) case ColumnType_BYTES: p := make([]byte, rng.Intn(10)) _, _ = rng.Read(p) return parser.NewDBytes(parser.DBytes(p)) case ColumnType_TIMESTAMPTZ: return &parser.DTimestampTZ{Time: time.Unix(rng.Int63n(1000000), rng.Int63n(1000000))} default: panic(fmt.Sprintf("invalid type %s", typ)) } }
// ShowColumns of a table. // Privileges: Any privilege on table. // Notes: postgres does not have a SHOW COLUMNS statement. // mysql only returns columns you have privileges on. func (p *planner) ShowColumns(n *parser.ShowColumns) (planNode, error) { tn, err := n.Table.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } desc, err := p.mustGetTableDesc(tn) if err != nil { return nil, err } if err := p.anyPrivilege(desc); err != nil { return nil, err } v := &valuesNode{ columns: []ResultColumn{ {Name: "Field", Typ: parser.TypeString}, {Name: "Type", Typ: parser.TypeString}, {Name: "Null", Typ: parser.TypeBool}, {Name: "Default", Typ: parser.TypeString}, }, } for i, col := range desc.Columns { defaultExpr := parser.DNull if e := desc.Columns[i].DefaultExpr; e != nil { defaultExpr = parser.NewDString(*e) } v.rows = append(v.rows, []parser.Datum{ parser.NewDString(desc.Columns[i].Name), parser.NewDString(col.Type.SQLString()), parser.MakeDBool(parser.DBool(desc.Columns[i].Nullable)), defaultExpr, }) } return v, nil }
func makePrefixRange(prefix parser.DString, datum parser.TypedExpr, complete bool) parser.TypedExpr { if complete { return parser.NewTypedComparisonExpr( parser.EQ, datum, &prefix, ) } if len(prefix) == 0 { return parser.MakeDBool(true) } return parser.NewTypedAndExpr( parser.NewTypedComparisonExpr( parser.GE, datum, &prefix, ), parser.NewTypedComparisonExpr( parser.LT, datum, parser.NewDString(string(roachpb.Key(prefix).PrefixEnd())), ), ) }
// decodeOidDatum decodes bytes with specified Oid and format code into // a datum. func decodeOidDatum(id oid.Oid, code formatCode, b []byte) (parser.Datum, error) { var d parser.Datum switch id { case oid.T_bool: switch code { case formatText: v, err := strconv.ParseBool(string(b)) if err != nil { return d, err } d = parser.MakeDBool(parser.DBool(v)) case formatBinary: switch b[0] { case 0: d = parser.MakeDBool(false) case 1: d = parser.MakeDBool(true) default: return d, util.Errorf("unsupported binary bool: %q", b) } default: return d, util.Errorf("unsupported bool format code: %s", code) } case oid.T_int2: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int16 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, util.Errorf("unsupported int2 format code: %s", code) } case oid.T_int4: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, util.Errorf("unsupported int4 format code: %s", code) } case oid.T_int8: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, util.Errorf("unsupported int8 format code: %s", code) } case oid.T_float4: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) case formatBinary: var f float32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) default: return d, util.Errorf("unsupported float4 format code: %s", code) } case oid.T_float8: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) case formatBinary: var f float64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) default: return d, util.Errorf("unsupported float8 format code: %s", code) } case oid.T_numeric: switch code { case formatText: dd := &parser.DDecimal{} if _, ok := dd.SetString(string(b)); !ok { return nil, util.Errorf("could not parse string %q as decimal", b) } d = dd case formatBinary: r := bytes.NewReader(b) alloc := struct { pgNum pgNumeric i16 int16 dd parser.DDecimal }{} for _, ptr := range []interface{}{ &alloc.pgNum.ndigits, &alloc.pgNum.weight, &alloc.pgNum.sign, &alloc.pgNum.dscale, } { if err := binary.Read(r, binary.BigEndian, ptr); err != nil { return d, err } } decDigits := make([]byte, 0, alloc.pgNum.ndigits*pgDecDigits) for i := int16(0); i < alloc.pgNum.ndigits-1; i++ { if err := binary.Read(r, binary.BigEndian, &alloc.i16); err != nil { return d, err } decDigits = strconv.AppendUint(decDigits, uint64(alloc.i16), 10) } // The last digit may contain padding, which we need to deal with. if err := binary.Read(r, binary.BigEndian, &alloc.i16); err != nil { return d, err } dscale := (alloc.pgNum.ndigits - 1 - alloc.pgNum.weight) * pgDecDigits if overScale := dscale - alloc.pgNum.dscale; overScale > 0 { dscale -= overScale for i := int16(0); i < overScale; i++ { alloc.i16 /= 10 } } decDigits = strconv.AppendUint(decDigits, uint64(alloc.i16), 10) alloc.dd.UnscaledBig().SetString(string(decDigits), 10) alloc.dd.SetScale(inf.Scale(dscale)) switch alloc.pgNum.sign { case pgNumericPos: case pgNumericNeg: alloc.dd.Neg(&alloc.dd.Dec) default: return d, util.Errorf("unsupported numeric sign: %s", alloc.pgNum.sign) } d = &alloc.dd default: return d, util.Errorf("unsupported numeric format code: %s", code) } case oid.T_text, oid.T_varchar: switch code { case formatText, formatBinary: d = parser.NewDString(string(b)) default: return d, util.Errorf("unsupported text format code: %s", code) } case oid.T_bytea: switch code { case formatText: // http://www.postgresql.org/docs/current/static/datatype-binary.html#AEN5667 // Code cribbed from github.com/lib/pq. // We only support hex encoding. if len(b) >= 2 && bytes.Equal(b[:2], []byte("\\x")) { b = b[2:] // trim off leading "\\x" result := make([]byte, hex.DecodedLen(len(b))) _, err := hex.Decode(result, b) if err != nil { return d, err } d = parser.NewDBytes(parser.DBytes(result)) } else { return d, util.Errorf("unsupported bytea encoding: %q", b) } case formatBinary: d = parser.NewDBytes(parser.DBytes(b)) default: return d, util.Errorf("unsupported bytea format code: %s", code) } case oid.T_timestamp, oid.T_timestamptz: switch code { case formatText: ts, err := parseTs(string(b)) if err != nil { return d, util.Errorf("could not parse string %q as timestamp", b) } d = parser.MakeDTimestamp(ts, time.Microsecond) default: return d, util.Errorf("unsupported timestamp format code: %s", code) } case oid.T_date: switch code { case formatText: ts, err := parseTs(string(b)) if err != nil { return d, util.Errorf("could not parse string %q as date", b) } daysSinceEpoch := ts.Unix() / secondsInDay d = parser.NewDDate(parser.DDate(daysSinceEpoch)) default: return d, util.Errorf("unsupported date format code: %s", code) } default: return d, util.Errorf("unsupported OID: %v", id) } return d, nil }
// UnmarshalColumnValue decodes the value from a key-value pair using the type // expected by the column. An error is returned if the value's type does not // match the column's type. func UnmarshalColumnValue( a *DatumAlloc, kind ColumnType_Kind, value *roachpb.Value, ) (parser.Datum, error) { if value == nil { return parser.DNull, nil } switch kind { case ColumnType_BOOL: v, err := value.GetInt() if err != nil { return nil, err } return parser.MakeDBool(parser.DBool(v != 0)), nil case ColumnType_INT: v, err := value.GetInt() if err != nil { return nil, err } return a.NewDInt(parser.DInt(v)), nil case ColumnType_FLOAT: v, err := value.GetFloat() if err != nil { return nil, err } return a.NewDFloat(parser.DFloat(v)), nil case ColumnType_DECIMAL: v, err := value.GetDecimal() if err != nil { return nil, err } dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(v) return dd, nil case ColumnType_STRING: v, err := value.GetBytes() if err != nil { return nil, err } return a.NewDString(parser.DString(v)), nil case ColumnType_BYTES: v, err := value.GetBytes() if err != nil { return nil, err } return a.NewDBytes(parser.DBytes(v)), nil case ColumnType_DATE: v, err := value.GetInt() if err != nil { return nil, err } return a.NewDDate(parser.DDate(v)), nil case ColumnType_TIMESTAMP: v, err := value.GetTime() if err != nil { return nil, err } return a.NewDTimestamp(parser.DTimestamp{Time: v}), nil case ColumnType_TIMESTAMPTZ: v, err := value.GetTime() if err != nil { return nil, err } return a.NewDTimestampTZ(parser.DTimestampTZ{Time: v}), nil case ColumnType_INTERVAL: d, err := value.GetDuration() if err != nil { return nil, err } return a.NewDInterval(parser.DInterval{Duration: d}), nil default: return nil, util.Errorf("unsupported column type: %s", kind) } }
// DecodeTableKey decodes a table key/value. func DecodeTableKey( a *DatumAlloc, valType parser.Datum, key []byte, dir encoding.Direction, ) (parser.Datum, []byte, error) { if (dir != encoding.Ascending) && (dir != encoding.Descending) { return nil, nil, util.Errorf("invalid direction: %d", dir) } var isNull bool if key, isNull = encoding.DecodeIfNull(key); isNull { return parser.DNull, key, nil } var rkey []byte var err error switch valType.(type) { case *parser.DBool: var i int64 if dir == encoding.Ascending { rkey, i, err = encoding.DecodeVarintAscending(key) } else { rkey, i, err = encoding.DecodeVarintDescending(key) } // No need to chunk allocate DBool as MakeDBool returns either // parser.DBoolTrue or parser.DBoolFalse. return parser.MakeDBool(parser.DBool(i != 0)), rkey, err case *parser.DInt: var i int64 if dir == encoding.Ascending { rkey, i, err = encoding.DecodeVarintAscending(key) } else { rkey, i, err = encoding.DecodeVarintDescending(key) } return a.NewDInt(parser.DInt(i)), rkey, err case *parser.DFloat: var f float64 if dir == encoding.Ascending { rkey, f, err = encoding.DecodeFloatAscending(key) } else { rkey, f, err = encoding.DecodeFloatDescending(key) } return a.NewDFloat(parser.DFloat(f)), rkey, err case *parser.DDecimal: var d *inf.Dec if dir == encoding.Ascending { rkey, d, err = encoding.DecodeDecimalAscending(key, nil) } else { rkey, d, err = encoding.DecodeDecimalDescending(key, nil) } dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(d) return dd, rkey, err case *parser.DString: var r string if dir == encoding.Ascending { rkey, r, err = encoding.DecodeUnsafeStringAscending(key, nil) } else { rkey, r, err = encoding.DecodeUnsafeStringDescending(key, nil) } return a.NewDString(parser.DString(r)), rkey, err case *parser.DBytes: var r []byte if dir == encoding.Ascending { rkey, r, err = encoding.DecodeBytesAscending(key, nil) } else { rkey, r, err = encoding.DecodeBytesDescending(key, nil) } return a.NewDBytes(parser.DBytes(r)), rkey, err case *parser.DDate: var t int64 if dir == encoding.Ascending { rkey, t, err = encoding.DecodeVarintAscending(key) } else { rkey, t, err = encoding.DecodeVarintDescending(key) } return a.NewDDate(parser.DDate(t)), rkey, err case *parser.DTimestamp: var t time.Time if dir == encoding.Ascending { rkey, t, err = encoding.DecodeTimeAscending(key) } else { rkey, t, err = encoding.DecodeTimeDescending(key) } return a.NewDTimestamp(parser.DTimestamp{Time: t}), rkey, err case *parser.DTimestampTZ: var t time.Time if dir == encoding.Ascending { rkey, t, err = encoding.DecodeTimeAscending(key) } else { rkey, t, err = encoding.DecodeTimeDescending(key) } return a.NewDTimestampTZ(parser.DTimestampTZ{Time: t}), rkey, err case *parser.DInterval: var d duration.Duration if dir == encoding.Ascending { rkey, d, err = encoding.DecodeDurationAscending(key) } else { rkey, d, err = encoding.DecodeDurationDescending(key) } return a.NewDInterval(parser.DInterval{Duration: d}), rkey, err default: return nil, nil, util.Errorf("TODO(pmattis): decoded index key: %s", valType.Type()) } }
// splitBoolExpr splits a boolean expression E into two boolean expressions RES and REM such that: // // - RES only has variables known to the conversion function (it is "restricted" to a particular // set of variables) // // - If weaker is true, for any setting of variables x: // E(x) = (RES(x) AND REM(x)) // This implies RES(x) <= E(x), i.e. RES is "weaker" // // - If weaker is false: // E(x) = (RES(x) OR REM(x)) // This implies RES(x) => E(x), i.e. RES is "stronger" func splitBoolExpr(expr parser.TypedExpr, conv varConvertFunc, weaker bool) (restricted, remainder parser.TypedExpr) { // If the expression only contains "restricted" vars, the split is trivial. if exprCheckVars(expr, conv) { // An "empty" filter is always true in the weaker (normal) case (where the filter is // equivalent to RES AND REM) and always false in the stronger (inverted) case (where the // filter is equivalent to RES OR REM). return exprConvertVars(expr, conv), parser.MakeDBool(parser.DBool(weaker)) } switch t := expr.(type) { case *parser.AndExpr: if weaker { // In the weaker (normal) case, we have // E = (leftRes AND leftRem) AND (rightRes AND rightRem) // We can just rearrange: // E = (leftRes AND rightRes) AND (leftRem AND rightRem) leftRes, leftRem := splitBoolExpr(t.TypedLeft(), conv, weaker) rightRes, rightRem := splitBoolExpr(t.TypedRight(), conv, weaker) return makeAnd(leftRes, rightRes), makeAnd(leftRem, rightRem) } // In the stronger (inverted) case, we have // E = (leftRes OR leftRem) AND (rightRes OR rightRem) // We can't do more than: // E = (leftRes AND rightRes) OR E leftRes, _ := splitBoolExpr(t.TypedLeft(), conv, weaker) rightRes, _ := splitBoolExpr(t.TypedRight(), conv, weaker) return makeAnd(leftRes, rightRes), expr case *parser.OrExpr: if !weaker { // In the stronger (inverted) case, we have // E = (leftRes OR leftRem) OR (rightRes AND rightRem) // We can just rearrange: // E = (leftRes OR rightRes) OR (leftRem AND rightRem) leftRes, leftRem := splitBoolExpr(t.TypedLeft(), conv, weaker) rightRes, rightRem := splitBoolExpr(t.TypedRight(), conv, weaker) return makeOr(leftRes, rightRes), makeOr(leftRem, rightRem) } // In the weaker (normal) case, we have // E = (leftRes AND leftRem) OR (rightRes AND rightRem) // We can't do more than: // E = (leftRes OR rightRes) OR E leftRes, _ := splitBoolExpr(t.TypedLeft(), conv, weaker) rightRes, _ := splitBoolExpr(t.TypedRight(), conv, weaker) return makeOr(leftRes, rightRes), expr case *parser.ParenExpr: return splitBoolExpr(t.TypedInnerExpr(), conv, weaker) case *parser.NotExpr: exprRes, exprRem := splitBoolExpr(t.TypedInnerExpr(), conv, !weaker) return makeNot(exprRes), makeNot(exprRem) default: // We can't split off anything (we already handled the case when expr contains only // restricted vars above). // For why we return DBool(weaker), see the comment above on "empty" filters. return parser.MakeDBool(parser.DBool(weaker)), expr } }
func (v *subqueryVisitor) VisitPre(expr parser.Expr) (recurse bool, newExpr parser.Expr) { if v.err != nil { return false, expr } v.path = append(v.path, expr) var exists *parser.ExistsExpr subquery, ok := expr.(*parser.Subquery) if !ok { exists, ok = expr.(*parser.ExistsExpr) if !ok { return true, expr } subquery, ok = exists.Subquery.(*parser.Subquery) if !ok { return true, expr } } // Calling makePlan() might recursively invoke expandSubqueries, so we need a // copy of the planner in order for there to have a separate subqueryVisitor. // TODO(nvanbenschoten) We should propagate a desired type here. // TODO(knz) the instantiation of the subquery's select node should be moved // to the TypeCheck() method once the prepare and execute phase are separated // for select nodes. planMaker := *v.planner plan, err := planMaker.makePlan(subquery.Select, nil, false) if err != nil { return false, expr } if v.evalCtx.PrepareOnly { return false, expr } if v.err = plan.Start(); v.err != nil { return false, expr } if exists != nil { // For EXISTS expressions, all we want to know is if there is at least one // result. if plan.Next() { return true, parser.MakeDBool(true) } v.err = plan.Err() if v.err != nil { return false, expr } return true, parser.MakeDBool(false) } columns, multipleRows := v.getSubqueryContext() if n := len(plan.Columns()); columns != n { switch columns { case 1: v.err = fmt.Errorf("subquery must return only one column, found %d", n) default: v.err = fmt.Errorf("subquery must return %d columns, found %d", columns, n) } return true, expr } var result parser.Expr if multipleRows { var rows parser.DTuple for plan.Next() { values := plan.Values() switch len(values) { case 1: // This seems hokey, but if we don't do this then the subquery expands // to a tuple of tuples instead of a tuple of values and an expression // like "k IN (SELECT foo FROM bar)" will fail because we're comparing // a single value against a tuple. rows = append(rows, values[0]) default: // The result from plan.Values() is only valid until the next call to // plan.Next(), so make a copy. valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) rows = append(rows, &valuesCopy) } } rows.Normalize() result = &rows } else { result = parser.DNull for plan.Next() { values := plan.Values() switch len(values) { case 1: result = values[0] default: valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) result = &valuesCopy } if plan.Next() { v.err = fmt.Errorf("more than one row returned by a subquery used as an expression") return false, expr } } } v.err = plan.Err() if v.err != nil { return false, expr } return true, result }
func simplifyOneOrExpr(left, right parser.TypedExpr) (parser.TypedExpr, parser.TypedExpr, bool) { lcmp, ok := left.(*parser.ComparisonExpr) if !ok { return left, right, true } rcmp, ok := right.(*parser.ComparisonExpr) if !ok { return left, right, true } lcmpLeft, lcmpRight := lcmp.TypedLeft(), lcmp.TypedRight() rcmpLeft, rcmpRight := rcmp.TypedLeft(), rcmp.TypedRight() if !isDatum(lcmpRight) || !isDatum(rcmpRight) { return parser.MakeDBool(true), nil, false } if !varEqual(lcmpLeft, rcmpLeft) { return left, right, true } if lcmp.Operator == parser.IsNot || rcmp.Operator == parser.IsNot { switch lcmp.Operator { case parser.Is: if lcmpRight == parser.DNull && rcmpRight == parser.DNull { // a IS NULL OR a IS NOT NULL return parser.MakeDBool(true), nil, true } case parser.IsNot: if lcmpRight == parser.DNull { switch rcmp.Operator { case parser.Is: if rcmpRight == parser.DNull { // a IS NOT NULL OR a IS NULL return parser.MakeDBool(true), nil, true } case parser.IsNot: if rcmpRight == parser.DNull { // a IS NOT NULL OR a IS NOT NULL return left, nil, true } } } } return left, right, true } if lcmp.Operator == parser.In || rcmp.Operator == parser.In { left, right = simplifyOneOrInExpr(lcmp, rcmp) return left, right, true } if reflect.TypeOf(lcmpRight) != reflect.TypeOf(rcmpRight) { allowCmp := false switch lcmp.Operator { case parser.EQ, parser.NE, parser.GT, parser.GE, parser.LT, parser.LE: switch rcmp.Operator { case parser.EQ, parser.NE, parser.GT, parser.GE, parser.LT, parser.LE: // Break, permitting heterogeneous comparison. allowCmp = true } } if !allowCmp { // If the types of the left and right datums are different, no // simplification is possible. return left, right, true } } ldatum := lcmpRight.(parser.Datum) rdatum := rcmpRight.(parser.Datum) cmp := ldatum.Compare(rdatum) // Determine which expression to use when either expression (left or right) // is valid as a return value but their types are different. The reason // to prefer a comparison between a column value and a datum of the same // type is that it makes index constraint construction easier. either := lcmp if !ldatum.TypeEqual(rdatum) { switch ta := lcmpLeft.(type) { case *qvalue: if ta.datum.TypeEqual(rdatum) { either = rcmp } } } // TODO(pmattis): Figure out how to generate this logic. switch lcmp.Operator { case parser.EQ: switch rcmp.Operator { case parser.EQ: // a = x OR a = y if cmp == 0 { // x = y return either, nil, true } else if cmp == 1 { // x > y ldatum, rdatum = rdatum, ldatum } return parser.NewTypedComparisonExpr( parser.In, lcmpLeft, &parser.DTuple{ldatum, rdatum}, ), nil, true case parser.NE: // a = x OR a != y if cmp == 0 { // x = y return makeIsNotNull(lcmpLeft), nil, true } return right, nil, true case parser.GT: // a = x OR a > y if cmp == 1 { // x > y OR x = y return right, nil, true } else if cmp == 0 { return parser.NewTypedComparisonExpr( parser.GE, lcmpLeft, either.TypedRight(), ), nil, true } return left, right, true case parser.GE: // a = x OR a >= y if cmp != -1 { // x >= y return right, nil, true } return left, right, true case parser.LT: // a = x OR a < y if cmp == -1 { // x < y OR x = y return right, nil, true } else if cmp == 0 { return parser.NewTypedComparisonExpr( parser.LE, lcmpLeft, either.TypedRight(), ), nil, true } return left, right, true case parser.LE: // a = x OR a <= y if cmp != 1 { // x <= y return right, nil, true } return left, right, true } case parser.NE: switch rcmp.Operator { case parser.EQ: // a != x OR a = y if cmp == 0 { // x = y return makeIsNotNull(lcmpLeft), nil, true } // x != y return left, nil, true case parser.NE: // a != x OR a != y if cmp == 0 { // x = y return either, nil, true } // x != y return makeIsNotNull(lcmpLeft), nil, true case parser.GT: // a != x OR a > y if cmp == 1 { // x > y return makeIsNotNull(lcmpLeft), nil, true } // x <= y return left, nil, true case parser.GE: // a != x OR a >= y if cmp != -1 { // x >= y return makeIsNotNull(lcmpLeft), nil, true } // x < y return left, nil, true case parser.LT: // a != x OR a < y if cmp == -1 { // x < y return makeIsNotNull(lcmpLeft), nil, true } // x >= y return left, nil, true case parser.LE: // a != x OR a <= y if cmp != 1 { // x <= y return makeIsNotNull(lcmpLeft), nil, true } // x > y return left, nil, true } case parser.GT: switch rcmp.Operator { case parser.EQ: // a > x OR a = y if cmp == -1 { // x < y return left, nil, true } else if cmp == 0 { return parser.NewTypedComparisonExpr( parser.GE, lcmpLeft, either.TypedRight(), ), nil, true } // x > y return left, right, true case parser.NE: // a > x OR a != y if cmp == -1 { // x < y return makeIsNotNull(lcmpLeft), nil, true } // x >= y return right, nil, true case parser.GT, parser.GE: // a > x OR (a > y OR a >= y) if cmp == -1 { return left, nil, true } return right, nil, true case parser.LT: // a > x OR a < y if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.NE, lcmpLeft, either.TypedRight(), ), nil, true } else if cmp == -1 { return makeIsNotNull(lcmpLeft), nil, true } // x != y return left, right, true case parser.LE: // a > x OR a <= y if cmp != 1 { // x = y return makeIsNotNull(lcmpLeft), nil, true } // x != y return left, right, true } case parser.GE: switch rcmp.Operator { case parser.EQ: // a >= x OR a = y if cmp != 1 { // x >. y return left, nil, true } // x < y return left, right, true case parser.NE: // a >= x OR a != y if cmp != 1 { // x <= y return makeIsNotNull(lcmpLeft), nil, true } // x > y return right, nil, true case parser.GT: // a >= x OR a > y if cmp != 1 { // x <= y return left, nil, true } // x > y return right, nil, true case parser.GE: // a >= x OR a >= y if cmp == -1 { // x < y return left, nil, true } // x >= y return right, nil, true case parser.LT, parser.LE: // a >= x OR a < y if cmp != 1 { // x <= y return makeIsNotNull(lcmpLeft), nil, true } // x > y return left, right, true } case parser.LT: switch rcmp.Operator { case parser.EQ: // a < x OR a = y if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.LE, lcmpLeft, either.TypedRight(), ), nil, true } else if cmp == 1 { // x > y return left, nil, true } // x < y return left, right, true case parser.NE: // a < x OR a != y if cmp == 1 { return makeIsNotNull(lcmpLeft), nil, true } return right, nil, true case parser.GT: // a < x OR a > y if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.NE, lcmpLeft, either.TypedRight(), ), nil, true } else if cmp == 1 { // x > y return makeIsNotNull(lcmpLeft), nil, true } return left, right, true case parser.GE: // a < x OR a >= y if cmp == -1 { // x < y return left, right, true } // x >= y return makeIsNotNull(lcmpLeft), nil, true case parser.LT, parser.LE: // a < x OR (a < y OR a <= y) if cmp == 1 { // x > y return left, nil, true } // x < y return right, nil, true } case parser.LE: switch rcmp.Operator { case parser.EQ: // a <= x OR a = y if cmp == -1 { // x < y return left, right, true } // x >= y return left, nil, true case parser.NE: // a <= x OR a != y if cmp != -1 { // x >= y return makeIsNotNull(lcmpLeft), nil, true } // x < y return right, nil, true case parser.GT, parser.GE: // a <= x OR (a > y OR a >= y) if cmp != -1 { // x >= y return makeIsNotNull(lcmpLeft), nil, true } // x < y return left, right, true case parser.LT, parser.LE: // a <= x OR a < y if cmp == -1 { // x < y return right, nil, true } // x >= y return left, nil, true } case parser.Is: switch rcmp.Operator { case parser.Is: if lcmpRight == parser.DNull && rcmpRight == parser.DNull { // a IS NULL OR a IS NULL return left, nil, true } } } return parser.MakeDBool(true), nil, false }
func simplifyOneAndInExpr(left, right *parser.ComparisonExpr) (parser.TypedExpr, parser.TypedExpr) { if left.Operator != parser.In && right.Operator != parser.In { panic(fmt.Sprintf("IN expression required: %s vs %s", left, right)) } origLeft, origRight := left, right switch left.Operator { case parser.EQ, parser.NE, parser.GT, parser.GE, parser.LT, parser.LE, parser.Is: switch right.Operator { case parser.In: left, right = right, left } fallthrough case parser.In: ltuple := *left.Right.(*parser.DTuple) switch right.Operator { case parser.Is: if right.Right == parser.DNull { return parser.MakeDBool(false), nil } case parser.EQ, parser.NE, parser.GT, parser.GE, parser.LT, parser.LE: // Our tuple will be sorted (see simplifyComparisonExpr). Binary search // for the right datum. datum := right.Right.(parser.Datum) i := sort.Search(len(ltuple), func(i int) bool { return ltuple[i].(parser.Datum).Compare(datum) >= 0 }) switch right.Operator { case parser.EQ: if i < len(ltuple) && ltuple[i].Compare(datum) == 0 { return right, nil } return parser.MakeDBool(false), nil case parser.NE: if i < len(ltuple) && ltuple[i].Compare(datum) == 0 { if len(ltuple) < 2 { return parser.MakeDBool(false), nil } ltuple = remove(ltuple, i) } return parser.NewTypedComparisonExpr( parser.In, left.TypedLeft(), <uple, ), nil case parser.GT: if i < len(ltuple) { if ltuple[i].Compare(datum) == 0 { ltuple = ltuple[i+1:] } else { ltuple = ltuple[i:] } if len(ltuple) > 0 { return parser.NewTypedComparisonExpr( parser.In, left.TypedLeft(), <uple, ), nil } } return parser.MakeDBool(false), nil case parser.GE: if i < len(ltuple) { ltuple = ltuple[i:] if len(ltuple) > 0 { return parser.NewTypedComparisonExpr( parser.In, left.TypedLeft(), <uple, ), nil } } return parser.MakeDBool(false), nil case parser.LT: if i < len(ltuple) { if i == 0 { return parser.MakeDBool(false), nil } ltuple = ltuple[:i] return parser.NewTypedComparisonExpr( parser.In, left.TypedLeft(), <uple, ), nil } return left, nil case parser.LE: if i < len(ltuple) { if ltuple[i].Compare(datum) == 0 { i++ } if i == 0 { return parser.MakeDBool(false), nil } ltuple = ltuple[:i] return parser.NewTypedComparisonExpr( parser.In, left.TypedLeft(), <uple, ), nil } return left, nil } case parser.In: // Both of our tuples are sorted. Intersect the lists. rtuple := *right.Right.(*parser.DTuple) intersection := intersectSorted(ltuple, rtuple) if len(*intersection) == 0 { return parser.MakeDBool(false), nil } return parser.NewTypedComparisonExpr( parser.In, left.TypedLeft(), intersection, ), nil } } return origLeft, origRight }
func simplifyOneAndExpr(left, right parser.TypedExpr) (parser.TypedExpr, parser.TypedExpr, bool) { lcmp, ok := left.(*parser.ComparisonExpr) if !ok { return left, right, true } rcmp, ok := right.(*parser.ComparisonExpr) if !ok { return left, right, true } lcmpLeft, lcmpRight := lcmp.TypedLeft(), lcmp.TypedRight() rcmpLeft, rcmpRight := rcmp.TypedLeft(), rcmp.TypedRight() if !isDatum(lcmpRight) || !isDatum(rcmpRight) { return parser.MakeDBool(true), nil, false } if !varEqual(lcmpLeft, rcmpLeft) { return left, right, true } if lcmp.Operator == parser.IsNot || rcmp.Operator == parser.IsNot { switch lcmp.Operator { case parser.EQ, parser.GT, parser.GE, parser.LT, parser.LE, parser.In: if rcmpRight == parser.DNull { // a <cmp> x AND a IS NOT NULL return left, nil, true } case parser.Is: if lcmpRight == parser.DNull && rcmpRight == parser.DNull { // a IS NULL AND a IS NOT NULL return parser.MakeDBool(false), nil, true } case parser.IsNot: if lcmpRight == parser.DNull { switch rcmp.Operator { case parser.EQ, parser.GT, parser.GE, parser.LT, parser.LE, parser.In: // a IS NOT NULL AND a <cmp> x return right, nil, true case parser.Is: if rcmpRight == parser.DNull { // a IS NOT NULL AND a IS NULL return parser.MakeDBool(false), nil, true } case parser.IsNot: if rcmpRight == parser.DNull { // a IS NOT NULL AND a IS NOT NULL return left, nil, true } } } } return left, right, true } if lcmp.Operator == parser.In || rcmp.Operator == parser.In { left, right = simplifyOneAndInExpr(lcmp, rcmp) return left, right, true } if reflect.TypeOf(lcmpRight) != reflect.TypeOf(rcmpRight) { allowCmp := false switch lcmp.Operator { case parser.EQ, parser.NE, parser.GT, parser.GE, parser.LT, parser.LE: switch rcmp.Operator { case parser.EQ, parser.NE, parser.GT, parser.GE, parser.LT, parser.LE: // Break, permitting heterogeneous comparison. allowCmp = true } } if !allowCmp { if lcmp.Operator == parser.Is && lcmpRight == parser.DNull { // a IS NULL AND a <cmp> x return parser.MakeDBool(false), nil, true } if rcmp.Operator == parser.Is && rcmpRight == parser.DNull { // a <cmp> x AND a IS NULL return parser.MakeDBool(false), nil, true } // Note that "a IS NULL and a IS NULL" cannot happen here because // "reflect.TypeOf(NULL) == reflect.TypeOf(NULL)". return left, right, true } } ldatum := lcmpRight.(parser.Datum) rdatum := rcmpRight.(parser.Datum) cmp := ldatum.Compare(rdatum) // Determine which expression to use when either expression (left or right) // is valid as a return value but their types are different. The reason // to prefer a comparison between a column value and a datum of the same // type is that it makes index constraint construction easier. either := lcmp if !ldatum.TypeEqual(rdatum) { switch ta := lcmpLeft.(type) { case *qvalue: if ta.datum.TypeEqual(rdatum) { either = rcmp } } } // TODO(pmattis): Figure out how to generate this logic. switch lcmp.Operator { case parser.EQ: switch rcmp.Operator { case parser.EQ: // a = x AND a = y if cmp == 0 { // x = y return either, nil, true } return parser.MakeDBool(false), nil, true case parser.NE: // a = x AND a != y if cmp == 0 { // x = y return parser.MakeDBool(false), nil, true } return left, nil, true case parser.GT, parser.GE: // a = x AND (a > y OR a >= y) if cmp == -1 || (cmp == 0 && rcmp.Operator == parser.GT) { // x < y OR x = y return parser.MakeDBool(false), nil, true } return left, nil, true case parser.LT, parser.LE: // a = x AND (a < y OR a <= y) if cmp == 1 || (cmp == 0 && rcmp.Operator == parser.LT) { // x > y OR x = y return parser.MakeDBool(false), nil, true } return left, nil, true } case parser.NE: switch rcmp.Operator { case parser.EQ: // a != x AND a = y if cmp == 0 { // x = y return parser.MakeDBool(false), nil, true } return right, nil, true case parser.NE: // a != x AND a != y if cmp == 0 { // x = y return either, nil, true } return left, right, true case parser.GT: // a != x AND a > y return right, nil, cmp <= 0 case parser.LT: // a != x AND a < y return right, nil, cmp >= 0 case parser.GE: // a != x AND a >= y if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.GT, rcmpLeft, either.TypedRight(), ), nil, true } // x != y return right, nil, cmp == -1 case parser.LE: // a != x AND a <= y if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.LT, rcmpLeft, either.TypedRight(), ), nil, true } // x != y return right, nil, cmp == +1 } case parser.GT: switch rcmp.Operator { case parser.EQ: // a > x AND a = y if cmp != -1 { // x >= y return parser.MakeDBool(false), nil, true } // x < y return right, nil, true case parser.NE: // a > x AND a != y return left, nil, cmp >= 0 case parser.GT, parser.GE: // a > x AND (a > y OR a >= y) if cmp != -1 { // x >= y return left, nil, true } // x < y return right, nil, true case parser.LT, parser.LE: // a > x AND (a < y OR a <= y) if cmp == -1 { // x < y return left, right, true } // x >= y return parser.MakeDBool(false), nil, true } case parser.GE: switch rcmp.Operator { case parser.EQ: // a >= x AND a = y if cmp == 1 { // x > y return parser.MakeDBool(false), nil, true } // x <= y return right, nil, true case parser.NE: // a >= x AND x != y if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.GT, lcmpLeft, either.TypedRight(), ), nil, true } // x != y return left, nil, cmp == +1 case parser.GT, parser.GE: // a >= x AND (a > y OR a >= y) if cmp == -1 || (cmp == 0 && rcmp.Operator == parser.GT) { // x < y return right, nil, true } // x >= y return left, nil, true case parser.LT: // a >= x AND a < y if cmp == -1 { // x < y return left, right, true } // x >= y return parser.MakeDBool(false), nil, true case parser.LE: // a >= x AND a <= y if cmp == -1 { // x < y return left, right, true } else if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.EQ, lcmpLeft, either.TypedRight(), ), nil, true } // x > y return parser.MakeDBool(false), nil, true } case parser.LT: switch rcmp.Operator { case parser.EQ: // a < x AND a = y if cmp != 1 { // x <= y return parser.MakeDBool(false), nil, true } // x > y return right, nil, true case parser.NE: // a < x AND a != y return left, nil, cmp <= 0 case parser.GT, parser.GE: // a < x AND (a > y OR a >= y) if cmp == 1 { // x > y return left, right, true } // x <= y return parser.MakeDBool(false), nil, true case parser.LT, parser.LE: // a < x AND (a < y OR a <= y) if cmp != 1 { // x <= y return left, nil, true } // x > y return right, nil, true } case parser.LE: switch rcmp.Operator { case parser.EQ: // a <= x AND a = y if cmp == -1 { // x < y return parser.MakeDBool(false), nil, true } // x >= y return right, nil, true case parser.NE: // a <= x AND a != y if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.LT, lcmpLeft, either.TypedRight(), ), nil, true } // x != y return left, nil, cmp == -1 case parser.GT: // a <= x AND a > y if cmp == 1 { // x > y return left, right, true } return parser.MakeDBool(false), nil, true case parser.GE: // a <= x AND a >= y if cmp == +1 { // x > y return left, right, true } else if cmp == 0 { // x = y return parser.NewTypedComparisonExpr( parser.EQ, lcmpLeft, either.TypedRight(), ), nil, true } // x < y return parser.MakeDBool(false), nil, true case parser.LT, parser.LE: // a <= x AND (a > y OR a >= y) if cmp == 1 || (cmp == 0 && rcmp.Operator == parser.LT) { // x > y return right, nil, true } // x <= y return left, nil, true } case parser.Is: switch rcmp.Operator { case parser.Is: if lcmpRight == parser.DNull && rcmpRight == parser.DNull { // a IS NULL AND a IS NULL return left, nil, true } } } return parser.MakeDBool(true), nil, false }
// decodeOidDatum decodes bytes with specified Oid and format code into // a datum. func decodeOidDatum(id oid.Oid, code formatCode, b []byte) (parser.Datum, error) { var d parser.Datum switch id { case oid.T_bool: switch code { case formatText: v, err := strconv.ParseBool(string(b)) if err != nil { return d, err } d = parser.MakeDBool(parser.DBool(v)) default: return d, fmt.Errorf("unsupported bool format code: %d", code) } case oid.T_int2: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int16 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, fmt.Errorf("unsupported int2 format code: %d", code) } case oid.T_int4: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, fmt.Errorf("unsupported int4 format code: %d", code) } case oid.T_int8: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, fmt.Errorf("unsupported int8 format code: %d", code) } case oid.T_float4: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) case formatBinary: var f float32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) default: return d, fmt.Errorf("unsupported float4 format code: %d", code) } case oid.T_float8: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) case formatBinary: var f float64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) default: return d, fmt.Errorf("unsupported float8 format code: %d", code) } case oid.T_numeric: switch code { case formatText: dd := &parser.DDecimal{} if _, ok := dd.SetString(string(b)); !ok { return nil, fmt.Errorf("could not parse string %q as decimal", b) } d = dd default: return d, fmt.Errorf("unsupported numeric format code: %d", code) } case oid.T_text, oid.T_varchar: switch code { case formatText: d = parser.NewDString(string(b)) default: return d, fmt.Errorf("unsupported text format code: %d", code) } case oid.T_bytea: switch code { case formatText: // http://www.postgresql.org/docs/current/static/datatype-binary.html#AEN5667 // Code cribbed from github.com/lib/pq. // We only support hex encoding. if len(b) >= 2 && bytes.Equal(b[:2], []byte("\\x")) { b = b[2:] // trim off leading "\\x" result := make([]byte, hex.DecodedLen(len(b))) _, err := hex.Decode(result, b) if err != nil { return d, err } d = parser.NewDBytes(parser.DBytes(result)) } else { return d, fmt.Errorf("unsupported bytea encoding: %q", b) } case formatBinary: d = parser.NewDBytes(parser.DBytes(b)) default: return d, fmt.Errorf("unsupported bytea format code: %d", code) } case oid.T_timestamp, oid.T_timestamptz: switch code { case formatText: ts, err := parseTs(string(b)) if err != nil { return d, fmt.Errorf("could not parse string %q as timestamp", b) } d = &parser.DTimestamp{Time: ts} case formatBinary: return d, fmt.Errorf("unsupported timestamp format code: %d", code) } case oid.T_date: switch code { case formatText: ts, err := parseTs(string(b)) if err != nil { return d, fmt.Errorf("could not parse string %q as date", b) } daysSinceEpoch := ts.Unix() / secondsInDay d = parser.NewDDate(parser.DDate(daysSinceEpoch)) case formatBinary: return d, fmt.Errorf("unsupported date format code: %d", code) } default: return d, fmt.Errorf("unsupported OID: %v", id) } return d, nil }
func (s *subquery) doEval() (parser.Datum, error) { var result parser.Datum switch s.execMode { case execModeExists: // For EXISTS expressions, all we want to know is if there is at least one // result. next, err := s.plan.Next() if s.err = err; err != nil { return result, err } if next { result = parser.MakeDBool(true) } if result == nil { result = parser.MakeDBool(false) } case execModeAllRows: var rows parser.DTuple next, err := s.plan.Next() for ; next; next, err = s.plan.Next() { values := s.plan.Values() switch len(values) { case 1: // This seems hokey, but if we don't do this then the subquery expands // to a tuple of tuples instead of a tuple of values and an expression // like "k IN (SELECT foo FROM bar)" will fail because we're comparing // a single value against a tuple. rows = append(rows, values[0]) default: // The result from plan.Values() is only valid until the next call to // plan.Next(), so make a copy. valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) rows = append(rows, &valuesCopy) } } if s.err = err; err != nil { return result, err } if s.wantNormalized { rows.Normalize() } result = &rows case execModeOneRow: result = parser.DNull next, err := s.plan.Next() if s.err = err; err != nil { return result, err } if next { values := s.plan.Values() switch len(values) { case 1: result = values[0] default: valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) result = &valuesCopy } another, err := s.plan.Next() if s.err = err; err != nil { return result, err } if another { s.err = fmt.Errorf("more than one row returned by a subquery used as an expression") return result, s.err } } } return result, nil }
func simplifyComparisonExpr(n *parser.ComparisonExpr) (parser.TypedExpr, bool) { // NormalizeExpr will have left comparisons in the form "<var> <op> // <datum>" unless they could not be simplified further in which case // simplifyExpr cannot handle them. For example, "lower(a) = 'foo'" left, right := n.TypedLeft(), n.TypedRight() if isVar(left) && isDatum(right) { if right == parser.DNull { switch n.Operator { case parser.IsNotDistinctFrom: switch left.(type) { case *qvalue, *parser.IndexedVar: // Transform "a IS NOT DISTINCT FROM NULL" into "a IS NULL". return parser.NewTypedComparisonExpr( parser.Is, left, right, ), true } case parser.IsDistinctFrom: switch left.(type) { case *qvalue, *parser.IndexedVar: // Transform "a IS DISTINCT FROM NULL" into "a IS NOT NULL". return parser.NewTypedComparisonExpr( parser.IsNot, left, right, ), true } case parser.Is, parser.IsNot: switch left.(type) { case *qvalue, *parser.IndexedVar: // "a IS {,NOT} NULL" can be used during index selection to restrict // the range of scanned keys. return n, true } default: // All of the remaining comparison operators have the property that when // comparing to NULL they evaluate to NULL (see evalComparisonOp). NULL is // not the same as false, but in the context of a WHERE clause, NULL is // considered not-true which is the same as false. return parser.MakeDBool(false), true } } switch n.Operator { case parser.EQ: // Translate "(a, b) = (1, 2)" to "(a, b) IN ((1, 2))". switch left.(type) { case *parser.Tuple: return parser.NewTypedComparisonExpr( parser.In, left, &parser.DTuple{right.(parser.Datum)}, ), true } return n, true case parser.NE, parser.GE, parser.LE: return n, true case parser.GT: // This simplification is necessary so that subsequent transformation of // > constraint to >= can use Datum.Next without concern about whether a // next value exists. Note that if the variable (n.Left) is NULL, this // comparison would evaluate to NULL which is equivalent to false for a // boolean expression. if right.(parser.Datum).IsMax() { return parser.MakeDBool(false), true } return n, true case parser.LT: // Note that if the variable is NULL, this would evaluate to NULL which // would equivalent to false for a boolean expression. if right.(parser.Datum).IsMin() { return parser.MakeDBool(false), true } return n, true case parser.In, parser.NotIn: tuple := *right.(*parser.DTuple) if len(tuple) == 0 { return parser.MakeDBool(false), true } return n, true case parser.Like: // a LIKE 'foo%' -> a >= "foo" AND a < "fop" if d, ok := right.(*parser.DString); ok { if i := strings.IndexAny(string(*d), "_%"); i >= 0 { return makePrefixRange((*d)[:i], left, false), false } return makePrefixRange(*d, left, true), false } // TODO(pmattis): Support parser.DBytes? case parser.SimilarTo: // a SIMILAR TO "foo.*" -> a >= "foo" AND a < "fop" if d, ok := right.(*parser.DString); ok { pattern := parser.SimilarEscape(string(*d)) if re, err := regexp.Compile(pattern); err == nil { prefix, complete := re.LiteralPrefix() return makePrefixRange(parser.DString(prefix), left, complete), false } } // TODO(pmattis): Support parser.DBytes? } } return parser.MakeDBool(true), false }
func dumpTable(w io.Writer, conn *sqlConn, origDBName, origTableName string) error { const limit = 100 // Escape names since they can't be used in placeholders. dbname := parser.Name(origDBName).String() tablename := parser.Name(origTableName).String() if err := conn.Exec(fmt.Sprintf("SET DATABASE = %s", dbname), nil); err != nil { return err } // Fetch all table metadata in a transaction and its time to guarantee it // doesn't change between the various SHOW statements. if err := conn.Exec("BEGIN", nil); err != nil { return err } vals, err := conn.QueryRow("SELECT cluster_logical_timestamp()::int", nil) if err != nil { return err } clusterTSStart := vals[0].(int64) clusterTS := time.Unix(0, clusterTSStart).Format(time.RFC3339Nano) // Fetch table descriptor. vals, err = conn.QueryRow(` SELECT descriptor FROM system.descriptor JOIN system.namespace tables ON tables.id = descriptor.id JOIN system.namespace dbs ON dbs.id = tables.parentid WHERE tables.name = $1 AND dbs.name = $2`, []driver.Value{origTableName, origDBName}) if err == io.EOF { return errors.Errorf("unknown database or table %s.%s", origTableName, origDBName) } else if err != nil { return err } b := vals[0].([]byte) var desc sqlbase.Descriptor if err := proto.Unmarshal(b, &desc); err != nil { return err } table := desc.GetTable() if table == nil { return errors.New("internal error: expected table descriptor") } coltypes := make(map[string]string) for _, c := range table.Columns { coltypes[c.Name] = c.Type.SQLString() } primaryIndex := table.PrimaryIndex.Name index := table.PrimaryIndex.ColumnNames indexes := strings.Join(index, ", ") // Build the SELECT query. var sbuf bytes.Buffer fmt.Fprintf(&sbuf, "SELECT %s, * FROM %s@%s AS OF SYSTEM TIME '%s'", indexes, tablename, primaryIndex, clusterTS) var wbuf bytes.Buffer fmt.Fprintf(&wbuf, " WHERE ROW (%s) > ROW (", indexes) for i := range index { if i > 0 { wbuf.WriteString(", ") } fmt.Fprintf(&wbuf, "$%d", i+1) } wbuf.WriteString(")") // No WHERE clause first time, so add a place to inject it. fmt.Fprintf(&sbuf, "%%s ORDER BY %s LIMIT %d", indexes, limit) bs := sbuf.String() vals, err = conn.QueryRow(fmt.Sprintf("SHOW CREATE TABLE %s", tablename), nil) if err != nil { return err } create := vals[1].([]byte) if _, err := w.Write(create); err != nil { return err } if _, err := w.Write([]byte(";\n")); err != nil { return err } if err := conn.Exec("COMMIT", nil); err != nil { return err } // pk holds the last values of the fetched primary keys var pk []driver.Value q := fmt.Sprintf(bs, "") for { rows, err := conn.Query(q, pk) if err != nil { return err } cols := rows.Columns() pkcols := cols[:len(index)] cols = cols[len(index):] inserts := make([][]string, 0, limit) i := 0 for i < limit { vals := make([]driver.Value, len(cols)+len(pkcols)) if err := rows.Next(vals); err == io.EOF { break } else if err != nil { return err } if pk == nil { q = fmt.Sprintf(bs, wbuf.String()) } pk = vals[:len(index)] vals = vals[len(index):] ivals := make([]string, len(vals)) // Values need to be correctly encoded for INSERT statements in a text file. for si, sv := range vals { switch t := sv.(type) { case nil: ivals[si] = "NULL" case bool: ivals[si] = parser.MakeDBool(parser.DBool(t)).String() case int64: ivals[si] = parser.NewDInt(parser.DInt(t)).String() case float64: ivals[si] = parser.NewDFloat(parser.DFloat(t)).String() case []byte: switch ct := coltypes[cols[si]]; ct { case "INTERVAL": ivals[si] = fmt.Sprintf("'%s'", t) case "DECIMAL": ivals[si] = fmt.Sprintf("%s", t) default: // STRING and BYTES types can have optional length suffixes, so only examine // the prefix of the type. if strings.HasPrefix(coltypes[cols[si]], "STRING") { ivals[si] = parser.NewDString(string(t)).String() } else if strings.HasPrefix(coltypes[cols[si]], "BYTES") { ivals[si] = parser.NewDBytes(parser.DBytes(t)).String() } else { panic(errors.Errorf("unknown []byte type: %s, %v: %s", t, cols[si], coltypes[cols[si]])) } } case time.Time: var d parser.Datum ct := coltypes[cols[si]] switch ct { case "DATE": d = parser.NewDDateFromTime(t, time.UTC) case "TIMESTAMP": d = parser.MakeDTimestamp(t, time.Nanosecond) case "TIMESTAMP WITH TIME ZONE": d = parser.MakeDTimestampTZ(t, time.Nanosecond) default: panic(errors.Errorf("unknown timestamp type: %s, %v: %s", t, cols[si], coltypes[cols[si]])) } ivals[si] = fmt.Sprintf("'%s'", d) default: panic(errors.Errorf("unknown field type: %T (%s)", t, cols[si])) } } inserts = append(inserts, ivals) i++ } for si, sv := range pk { b, ok := sv.([]byte) if ok && strings.HasPrefix(coltypes[pkcols[si]], "STRING") { // Primary key strings need to be converted to a go string, but not SQL // encoded since they aren't being written to a text file. pk[si] = string(b) } } if err := rows.Close(); err != nil { return err } if i == 0 { break } fmt.Fprintf(w, "\nINSERT INTO %s VALUES", tablename) for idx, values := range inserts { if idx > 0 { fmt.Fprint(w, ",") } fmt.Fprint(w, "\n\t(") for vi, v := range values { if vi > 0 { fmt.Fprint(w, ", ") } fmt.Fprint(w, v) } fmt.Fprint(w, ")") } fmt.Fprintln(w, ";") if i < limit { break } } return nil }
func TestValues(t *testing.T) { defer leaktest.AfterTest(t)() p := makePlanner() vInt := int64(5) vNum := 3.14159 vStr := "two furs one cub" vBool := true unsupp := &parser.RangeCond{} intVal := func(v int64) *parser.NumVal { return &parser.NumVal{Value: constant.MakeInt64(v)} } floatVal := func(f float64) *parser.CastExpr { return &parser.CastExpr{ Expr: &parser.NumVal{Value: constant.MakeFloat64(f)}, Type: &parser.FloatColType{}, } } asRow := func(datums ...parser.Datum) []parser.DTuple { return []parser.DTuple{datums} } makeValues := func(tuples ...*parser.Tuple) *parser.ValuesClause { return &parser.ValuesClause{Tuples: tuples} } makeTuple := func(exprs ...parser.Expr) *parser.Tuple { return &parser.Tuple{Exprs: exprs} } testCases := []struct { stmt *parser.ValuesClause rows []parser.DTuple ok bool }{ { makeValues(makeTuple(intVal(vInt))), asRow(parser.NewDInt(parser.DInt(vInt))), true, }, { makeValues(makeTuple(intVal(vInt), intVal(vInt))), asRow(parser.NewDInt(parser.DInt(vInt)), parser.NewDInt(parser.DInt(vInt))), true, }, { makeValues(makeTuple(floatVal(vNum))), asRow(parser.NewDFloat(parser.DFloat(vNum))), true, }, { makeValues(makeTuple(parser.NewDString(vStr))), asRow(parser.NewDString(vStr)), true, }, { makeValues(makeTuple(parser.NewDBytes(parser.DBytes(vStr)))), asRow(parser.NewDBytes(parser.DBytes(vStr))), true, }, { makeValues(makeTuple(parser.MakeDBool(parser.DBool(vBool)))), asRow(parser.MakeDBool(parser.DBool(vBool))), true, }, { makeValues(makeTuple(unsupp)), nil, false, }, } for i, tc := range testCases { plan, err := func() (_ planNode, err error) { defer func() { if r := recover(); r != nil { err = errors.Errorf("%v", r) } }() return p.ValuesClause(tc.stmt, nil) }() if err == nil != tc.ok { t.Errorf("%d: error_expected=%t, but got error %v", i, tc.ok, err) } if plan != nil { if err := plan.expandPlan(); err != nil { t.Errorf("%d: unexpected error in expandPlan: %v", i, err) continue } if err := plan.Start(); err != nil { t.Errorf("%d: unexpected error in Start: %v", i, err) continue } var rows []parser.DTuple next, err := plan.Next() for ; next; next, err = plan.Next() { rows = append(rows, plan.Values()) } if err != nil { t.Error(err) continue } if !reflect.DeepEqual(rows, tc.rows) { t.Errorf("%d: expected rows:\n%+v\nactual rows:\n%+v", i, tc.rows, rows) } } } }
func dumpTable(w io.Writer, conn *sqlConn, origDBName, origTableName string) error { const limit = 100 // Escape names since they can't be used in placeholders. dbname := parser.Name(origDBName).String() tablename := parser.Name(origTableName).String() if err := conn.Exec(fmt.Sprintf("SET DATABASE = %s", dbname), nil); err != nil { return err } // Fetch all table metadata in a transaction and its time to guarantee it // doesn't change between the various SHOW statements. if err := conn.Exec("BEGIN", nil); err != nil { return err } vals, err := conn.QueryRow("SELECT cluster_logical_timestamp()::int", nil) if err != nil { return err } clusterTSStart := vals[0].(int64) clusterTS := time.Unix(0, clusterTSStart).Format(time.RFC3339Nano) // A previous version of the code did a SELECT on system.descriptor. This // required the SELECT privilege to the descriptor table, which only root // has. Allowing non-root to do this would let users see other users' table // descriptors which is a problem in multi-tenancy. // Fetch column types. rows, err := conn.Query(fmt.Sprintf("SHOW COLUMNS FROM %s", tablename), nil) if err != nil { return err } vals = make([]driver.Value, 2) coltypes := make(map[string]string) for { if err := rows.Next(vals); err == io.EOF { break } else if err != nil { return err } name, ok := vals[0].(string) if !ok { return fmt.Errorf("unexpected value: %T", vals[1]) } typ, ok := vals[1].(string) if !ok { return fmt.Errorf("unexpected value: %T", vals[4]) } coltypes[name] = typ } if err := rows.Close(); err != nil { return err } // index holds the names, in order, of the primary key columns. var index []string // Primary index is always the first index returned by SHOW INDEX. rows, err = conn.Query(fmt.Sprintf("SHOW INDEX FROM %s", tablename), nil) if err != nil { return err } vals = make([]driver.Value, 5) var primaryIndex string // Find the primary index columns. for { if err := rows.Next(vals); err == io.EOF { break } else if err != nil { return err } b, ok := vals[1].(string) if !ok { return fmt.Errorf("unexpected value: %T", vals[1]) } if primaryIndex == "" { primaryIndex = b } else if primaryIndex != b { break } b, ok = vals[4].(string) if !ok { return fmt.Errorf("unexpected value: %T", vals[4]) } index = append(index, parser.Name(b).String()) } if err := rows.Close(); err != nil { return err } if len(index) == 0 { return fmt.Errorf("no primary key index found") } indexes := strings.Join(index, ", ") // Build the SELECT query. var sbuf bytes.Buffer fmt.Fprintf(&sbuf, "SELECT %s, * FROM %s@%s AS OF SYSTEM TIME '%s'", indexes, tablename, primaryIndex, clusterTS) var wbuf bytes.Buffer fmt.Fprintf(&wbuf, " WHERE ROW (%s) > ROW (", indexes) for i := range index { if i > 0 { wbuf.WriteString(", ") } fmt.Fprintf(&wbuf, "$%d", i+1) } wbuf.WriteString(")") // No WHERE clause first time, so add a place to inject it. fmt.Fprintf(&sbuf, "%%s ORDER BY %s LIMIT %d", indexes, limit) bs := sbuf.String() vals, err = conn.QueryRow(fmt.Sprintf("SHOW CREATE TABLE %s", tablename), nil) if err != nil { return err } create := vals[1].(string) if _, err := w.Write([]byte(create)); err != nil { return err } if _, err := w.Write([]byte(";\n")); err != nil { return err } if err := conn.Exec("COMMIT", nil); err != nil { return err } // pk holds the last values of the fetched primary keys var pk []driver.Value q := fmt.Sprintf(bs, "") for { rows, err := conn.Query(q, pk) if err != nil { return err } cols := rows.Columns() pkcols := cols[:len(index)] cols = cols[len(index):] inserts := make([][]string, 0, limit) i := 0 for i < limit { vals := make([]driver.Value, len(cols)+len(pkcols)) if err := rows.Next(vals); err == io.EOF { break } else if err != nil { return err } if pk == nil { q = fmt.Sprintf(bs, wbuf.String()) } pk = vals[:len(index)] vals = vals[len(index):] ivals := make([]string, len(vals)) // Values need to be correctly encoded for INSERT statements in a text file. for si, sv := range vals { switch t := sv.(type) { case nil: ivals[si] = "NULL" case bool: ivals[si] = parser.MakeDBool(parser.DBool(t)).String() case int64: ivals[si] = parser.NewDInt(parser.DInt(t)).String() case float64: ivals[si] = parser.NewDFloat(parser.DFloat(t)).String() case string: ivals[si] = parser.NewDString(t).String() case []byte: switch ct := coltypes[cols[si]]; ct { case "INTERVAL": ivals[si] = fmt.Sprintf("'%s'", t) case "BYTES": ivals[si] = parser.NewDBytes(parser.DBytes(t)).String() default: // STRING and DECIMAL types can have optional length // suffixes, so only examine the prefix of the type. if strings.HasPrefix(coltypes[cols[si]], "STRING") { ivals[si] = parser.NewDString(string(t)).String() } else if strings.HasPrefix(coltypes[cols[si]], "DECIMAL") { ivals[si] = string(t) } else { panic(errors.Errorf("unknown []byte type: %s, %v: %s", t, cols[si], coltypes[cols[si]])) } } case time.Time: var d parser.Datum ct := coltypes[cols[si]] switch ct { case "DATE": d = parser.NewDDateFromTime(t, time.UTC) case "TIMESTAMP": d = parser.MakeDTimestamp(t, time.Nanosecond) case "TIMESTAMP WITH TIME ZONE": d = parser.MakeDTimestampTZ(t, time.Nanosecond) default: panic(errors.Errorf("unknown timestamp type: %s, %v: %s", t, cols[si], coltypes[cols[si]])) } ivals[si] = fmt.Sprintf("'%s'", d) default: panic(errors.Errorf("unknown field type: %T (%s)", t, cols[si])) } } inserts = append(inserts, ivals) i++ } for si, sv := range pk { b, ok := sv.([]byte) if ok && strings.HasPrefix(coltypes[pkcols[si]], "STRING") { // Primary key strings need to be converted to a go string, but not SQL // encoded since they aren't being written to a text file. pk[si] = string(b) } } if err := rows.Close(); err != nil { return err } if i == 0 { break } fmt.Fprintf(w, "\nINSERT INTO %s VALUES", tablename) for idx, values := range inserts { if idx > 0 { fmt.Fprint(w, ",") } fmt.Fprint(w, "\n\t(") for vi, v := range values { if vi > 0 { fmt.Fprint(w, ", ") } fmt.Fprint(w, v) } fmt.Fprint(w, ")") } fmt.Fprintln(w, ";") if i < limit { break } } return nil }