// DecodeTableValue decodes a value encoded by EncodeTableValue. func DecodeTableValue(a *DatumAlloc, valType parser.Type, 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 { case parser.TypeBool: 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.TypeInt: var i int64 b, i, err = encoding.DecodeIntValue(b) return a.NewDInt(parser.DInt(i)), b, err case parser.TypeFloat: var f float64 b, f, err = encoding.DecodeFloatValue(b) return a.NewDFloat(parser.DFloat(f)), b, err case parser.TypeDecimal: var d *inf.Dec b, d, err = encoding.DecodeDecimalValue(b) dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(d) return dd, b, err case parser.TypeString: var data []byte b, data, err = encoding.DecodeBytesValue(b) return a.NewDString(parser.DString(data)), b, err case parser.TypeBytes: var data []byte b, data, err = encoding.DecodeBytesValue(b) return a.NewDBytes(parser.DBytes(data)), b, err case parser.TypeDate: var i int64 b, i, err = encoding.DecodeIntValue(b) return a.NewDDate(parser.DDate(i)), b, err case parser.TypeTimestamp: var t time.Time b, t, err = encoding.DecodeTimeValue(b) return a.NewDTimestamp(parser.DTimestamp{Time: t}), b, err case parser.TypeTimestampTZ: var t time.Time b, t, err = encoding.DecodeTimeValue(b) return a.NewDTimestampTZ(parser.DTimestampTZ{Time: t}), b, err case parser.TypeInterval: 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) } }
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 *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 *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 *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 }
// DecodeTableKey decodes a table key/value. func DecodeTableKey( a *DatumAlloc, valType parser.Type, key []byte, dir encoding.Direction, ) (parser.Datum, []byte, error) { if (dir != encoding.Ascending) && (dir != encoding.Descending) { return nil, nil, errors.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 { case parser.TypeBool: 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.TypeInt: 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.TypeFloat: 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.TypeDecimal: 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.TypeString: 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.TypeBytes: 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.TypeDate: 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.TypeTimestamp: 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.TypeTimestampTZ: 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.TypeInterval: 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, errors.Errorf("TODO(pmattis): decoded index key: %s", valType) } }
// 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.GetBool() if err != nil { return nil, err } return parser.MakeDBool(parser.DBool(v)), 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, errors.Errorf("unsupported column type: %s", kind) } }