Merge "syncbase: syncQL: replace t with Type(), remove restrictions on k"
diff --git a/v23/syncbase/nosql/client_test.go b/v23/syncbase/nosql/client_test.go
index bca7a84..bd60315 100644
--- a/v23/syncbase/nosql/client_test.go
+++ b/v23/syncbase/nosql/client_test.go
@@ -84,7 +84,7 @@
t.Fatalf("tb.Put() failed: %v", err)
}
- tu.CheckExec(t, ctx, d, "select k, v.Name from tb where t = \"Baz\"",
+ tu.CheckExec(t, ctx, d, "select k, v.Name from tb where Type(v) = \"Baz\"",
[]string{"k", "v.Name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz.Name)},
@@ -111,7 +111,7 @@
[]*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz)},
})
- tu.CheckExec(t, ctx, d, "select k, v from tb where t = \"Bar\"",
+ tu.CheckExec(t, ctx, d, "select k, v from tb where Type(v) = \"Bar\"",
[]string{"k", "v"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("bar"), vdl.ValueOf(bar)},
@@ -123,7 +123,7 @@
[]*vdl.Value{vdl.ValueOf("bar"), vdl.ValueOf(bar)},
})
- tu.CheckExec(t, ctx, d, "select k, v from tb where t = \"Baz\"",
+ tu.CheckExec(t, ctx, d, "select k, v from tb where Type(v) = \"Baz\"",
[]string{"k", "v"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz)},
diff --git a/v23/syncbase/nosql/exec_test/exec_test.go b/v23/syncbase/nosql/exec_test/exec_test.go
index 1909634..645b575 100644
--- a/v23/syncbase/nosql/exec_test/exec_test.go
+++ b/v23/syncbase/nosql/exec_test/exec_test.go
@@ -229,7 +229,7 @@
basic := []execSelectTest{
{
// Select values for all customer records.
- "select v from Customer where t = \"Customer\"",
+ "select v from Customer where Type(v) = \"Customer\"",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{customerEntries[0].value},
@@ -329,7 +329,7 @@
},
{
// Select keys & values for all customer records.
- "select k, v from Customer where t = \"Customer\"",
+ "select k, v from Customer where Type(v) = \"Customer\"",
[]string{"k", "v"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(customerEntries[0].key), customerEntries[0].value},
@@ -339,7 +339,7 @@
},
{
// Select keys & names for all customer records.
- "select k, v.Name from Customer where t = \"Customer\"",
+ "select k, v.Name from Customer where Type(v) = \"Customer\"",
[]string{"k", "v.Name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(customerEntries[0].key), vdl.ValueOf("John Smith")},
@@ -368,7 +368,7 @@
},
{
// Select keys & values fo all invoice records.
- "select k, v from Customer where t = \"Invoice\"",
+ "select k, v from Customer where Type(v) = \"Invoice\"",
[]string{"k", "v"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(customerEntries[1].key), customerEntries[1].value},
@@ -382,7 +382,7 @@
},
{
// Select key, cust id, invoice number and amount for $88 invoices.
- "select k, v.CustId as ID, v.InvoiceNum as InvoiceNumber, v.Amount as Amt from Customer where t = \"Invoice\" and v.Amount = 88",
+ "select k, v.CustId as ID, v.InvoiceNum as InvoiceNumber, v.Amount as Amt from Customer where Type(v) = \"Invoice\" and v.Amount = 88",
[]string{"k", "ID", "InvoiceNumber", "Amt"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(customerEntries[3].key), vdl.ValueOf(int64(1)), vdl.ValueOf(int64(1005)), vdl.ValueOf(int64(88))},
@@ -510,7 +510,7 @@
},
{
// Select id, name for customers whose last name is Masterson.
- "select v.Id as ID, v.Name as Name from Customer where t = \"Customer\" and v.Name like \"%Masterson\"",
+ "select v.Id as ID, v.Name as Name from Customer where Type(v) = \"Customer\" and v.Name like \"%Masterson\"",
[]string{"ID", "Name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(int64(2)), vdl.ValueOf("Bat Masterson")},
@@ -518,7 +518,7 @@
},
{
// Select records where v.Address.City is "Collins" or type is Invoice.
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\"",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\"",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{customerEntries[1].value},
@@ -547,7 +547,7 @@
},
{
// Select customer name for customer Id (i.e., key) "001".
- "select v.Name as Name from Customer where t = \"Customer\" and k = \"001\"",
+ "select v.Name as Name from Customer where Type(v) = \"Customer\" and k = \"001\"",
[]string{"Name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("John Smith")},
@@ -596,7 +596,7 @@
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Limit 3
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" limit 3",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" limit 3",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{customerEntries[1].value},
@@ -607,7 +607,7 @@
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Offset 5
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" offset 5",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" offset 5",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{customerEntries[6].value},
@@ -624,21 +624,21 @@
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Offset 8
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" offset 8",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" offset 8",
[]string{"v"},
[][]*vdl.Value{},
},
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Offset 23
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" offset 23",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" offset 23",
[]string{"v"},
[][]*vdl.Value{},
},
{
// Select records where v.Address.City = "Collins" is 84 or type is Invoice.
// Limit 3 Offset 2
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" limit 3 offset 2",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" limit 3 offset 2",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{customerEntries[3].value},
@@ -649,7 +649,7 @@
{
// Select records where v.Address.City = "Collins" or (type is Invoice and v.InvoiceNum is not nil).
// Limit 3 Offset 2
- "select v from Customer where v.Address.City = \"Collins\" or (t = \"Invoice\" and v.InvoiceNum is not nil) limit 3 offset 2",
+ "select v from Customer where v.Address.City = \"Collins\" or (Type(v) = \"Invoice\" and v.InvoiceNum is not nil) limit 3 offset 2",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{customerEntries[3].value},
@@ -660,14 +660,14 @@
{
// Select records where v.Address.City = "Collins" or (type is Invoice and v.InvoiceNum is nil).
// Limit 3 Offset 2
- "select v from Customer where v.Address.City = \"Collins\" or (t = \"Invoice\" and v.InvoiceNum is nil) limit 3 offset 2",
+ "select v from Customer where v.Address.City = \"Collins\" or (Type(v) = \"Invoice\" and v.InvoiceNum is nil) limit 3 offset 2",
[]string{"v"},
[][]*vdl.Value{},
},
// Test functions.
{
// Select invoice records where date is 2015-03-17
- "select v from Customer where t = \"Invoice\" and YMD(v.InvoiceDate, \"America/Los_Angeles\") = Date(\"2015-03-17 PDT\")",
+ "select v from Customer where Type(v) = \"Invoice\" and YMD(v.InvoiceDate, \"America/Los_Angeles\") = Date(\"2015-03-17 PDT\")",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{customerEntries[5].value},
@@ -763,7 +763,7 @@
// Test string functions in where clause.
{
// Select invoices shipped to Any street -- using LowerCase.
- "select k from Customer where t = \"Invoice\" and LowerCase(v.ShipTo.Street) like \"%any%\"",
+ "select k from Customer where Type(v) = \"Invoice\" and LowerCase(v.ShipTo.Street) like \"%any%\"",
[]string{"k"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(customerEntries[5].key)},
@@ -774,7 +774,7 @@
},
{
// Select invoices shipped to Any street -- using UpperCase.
- "select k from Customer where t = \"Invoice\" and UpperCase(v.ShipTo.Street) like \"%ANY%\"",
+ "select k from Customer where Type(v) = \"Invoice\" and UpperCase(v.ShipTo.Street) like \"%ANY%\"",
[]string{"k"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(customerEntries[5].key)},
@@ -820,7 +820,7 @@
},
// LowerCase function
{
- "select LowerCase(v.Name) as name from Customer where t = \"Customer\"",
+ "select LowerCase(v.Name) as name from Customer where Type(v) = \"Customer\"",
[]string{"name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("john smith")},
@@ -830,7 +830,7 @@
},
// UpperCase function
{
- "select UpperCase(v.Name) as NAME from Customer where t = \"Customer\"",
+ "select UpperCase(v.Name) as NAME from Customer where Type(v) = \"Customer\"",
[]string{"NAME"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("JOHN SMITH")},
@@ -840,7 +840,7 @@
},
// YMDHMS function
{
- "select k, YMDHMS(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMDHMS(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMDHMS",
@@ -851,7 +851,7 @@
},
// YMDHM function
{
- "select k, YMDHM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMDHM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMDHM",
@@ -862,7 +862,7 @@
},
// YMDH function
{
- "select k, YMDH(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMDH(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMDH",
@@ -873,7 +873,7 @@
},
// YMD function
{
- "select k, YMD(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMD(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMD",
@@ -884,7 +884,7 @@
},
// YM function
{
- "select k, YM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YM",
@@ -895,7 +895,7 @@
},
// Y function
{
- "select k, Y(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"001001\"",
+ "select k, Y(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"001001\"",
[]string{
"k",
"Y",
@@ -906,7 +906,7 @@
},
// Nested functions
{
- "select Y(YM(YMD(YMDH(YMDHM(YMDHMS(v.InvoiceDate, \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"001001\"",
+ "select Y(YM(YMD(YMDH(YMDHM(YMDHMS(v.InvoiceDate, \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"001001\"",
[]string{"Y"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(t2015)},
@@ -914,7 +914,7 @@
},
// Bad arg to function. Expression is false.
{
- "select v from Customer where t = \"Invoice\" and YMD(v.InvoiceDate, v.Foo) = v.InvoiceDate",
+ "select v from Customer where Type(v) = \"Invoice\" and YMD(v.InvoiceDate, v.Foo) = v.InvoiceDate",
[]string{"v"},
[][]*vdl.Value{},
},
diff --git a/v23/syncbase/nosql/internal/query/eval.go b/v23/syncbase/nosql/internal/query/eval.go
index b33e975..1ab48c0 100644
--- a/v23/syncbase/nosql/internal/query/eval.go
+++ b/v23/syncbase/nosql/internal/query/eval.go
@@ -303,14 +303,24 @@
}
}
+// Return AltStr if available, else Str.
+// Must be called with an operand of type TypStr.
+func favorAltStr(strOp *query_parser.Operand) string {
+ if !strOp.HasAltStr {
+ return strOp.Str
+ }
+ return strOp.AltStr
+}
+
func compareStrings(lhsValue, rhsValue *query_parser.Operand, oper *query_parser.BinaryOperator) bool {
switch oper.Type {
case query_parser.Equal:
r := lhsValue.Str == rhsValue.Str
- // Handle special case for type equal clauses.
- // Only the lhs can have the AltStr field set.
- if !r && lhsValue.HasAltStr {
- r = lhsValue.AltStr == rhsValue.Str
+ // If either side has an AltStr, compare AltStr.
+ // If both have AltStr, compare altStr to AltStr.
+ if !r && lhsValue.HasAltStr || rhsValue.HasAltStr {
+ // Handle special case for Type functions (which have AltStr)
+ r = favorAltStr(lhsValue) == favorAltStr(rhsValue)
}
return r
case query_parser.NotEqual:
@@ -397,7 +407,7 @@
if o.Type != query_parser.TypField {
return o
}
- value, hasAltStr, altStr := ResolveField(db, k, v, o.Column)
+ value := ResolveField(db, k, v, o.Column)
if value.IsNil() {
return nil
}
@@ -429,8 +439,7 @@
case vdl.String:
newOp.Type = query_parser.TypStr
newOp.Str = value.RawString()
- newOp.HasAltStr = hasAltStr
- newOp.AltStr = altStr
+ newOp.HasAltStr = false
case vdl.Complex64, vdl.Complex128:
newOp.Type = query_parser.TypComplex
newOp.Complex = value.Complex()
@@ -551,23 +560,13 @@
return nil
}
-// Resolve a field. In the special case where a type is evaluated, in addition
-// to a string being returned, and alternate string is returned. In this case,
-// <string-value>, true, <alt-string> is returned. In all other cases,
-// <value>,false,"" is returned.
-func ResolveField(db query_db.Database, k string, v *vdl.Value, f *query_parser.Field) (*vdl.Value, bool, string) {
+// Resolve a field.
+func ResolveField(db query_db.Database, k string, v *vdl.Value, f *query_parser.Field) *vdl.Value {
if query_checker.IsKeyField(f) {
- return vdl.StringValue(k), false, ""
+ return vdl.StringValue(k)
}
// Auto-dereference Any and Optional values
v = autoDereference(v)
- t := v.Type()
- if query_checker.IsTypeField(f) {
- // Types evaluate to two strings, Str and AltStr.
- // This is because types match on full path or just the name.
- pkg, name := vdl.SplitIdent(t.Name())
- return vdl.StringValue(pkg + "." + name), true, name
- }
object := v
segments := f.Segments
@@ -581,7 +580,7 @@
// object must be a struct in order to look for the next segment.
if object.Kind() == vdl.Struct {
if object = object.StructFieldByName(segments[i].Value); object == nil {
- return vdl.ValueOf(nil), false, "" // field does not exist
+ return vdl.ValueOf(nil)
}
object = resolveWithKey(db, k, v, object, segments[i])
} else if object.Kind() == vdl.Union {
@@ -590,14 +589,14 @@
if segments[i].Value == unionType.Field(idx).Name {
object = tempValue
} else {
- return vdl.ValueOf(nil), false, "" // union field does not exist or is not set
+ return vdl.ValueOf(nil)
}
object = resolveWithKey(db, k, v, object, segments[i])
} else {
- return vdl.ValueOf(nil), false, "" // can only traverse into structs and unions
+ return vdl.ValueOf(nil)
}
}
- return object, false, ""
+ return object
}
// EvalWhereUsingOnlyKey return type. See that function for details.
@@ -614,12 +613,12 @@
// INCLUDE: the row should included in the results
// EXCLUDE: the row should NOT be included
// FETCH_VALUE: the value and/or type of the value are required to determine if row should be included.
-// The above decision is accomplished by evaluating all expressions which reference the key and
-// substituing false for all other expressions. If the result is true, INCLUDE is returned.
-// If the result is false, but no other expressions (i.e., expressions which refer to the type
-// of the value or the value itself) were encountered, EXCLUDE is returned; else, FETCH_VALUE is
-// returned indicating the value must be fetched in order to determine if the row should be included
-// in the results.
+// The above decision is accomplished by evaluating all expressions which compare the key
+// with a string literal and substituing false for all other expressions. If the result is true,
+// INCLUDE is returned.
+// If the result is false, but no other expressions were encountered, EXCLUDE is returned; else,
+// FETCH_VALUE is returned indicating the value must be fetched in order to determine if the row
+// should be included in the results.
func EvalWhereUsingOnlyKey(db query_db.Database, s *query_parser.SelectStatement, k string) EvalWithKeyResult {
if s.Where == nil { // all rows will be in result
return INCLUDE
@@ -651,11 +650,16 @@
} else {
return FETCH_VALUE
}
- default: // =, > >=, <, <=, Like, <>, NotLike
- if !query_checker.IsKey(e.Operand1) {
+ default:
+ if !query_checker.ContainsKeyOperand(e) {
return FETCH_VALUE
} else {
- if evalComparisonOperators(db, k, nil, e) {
+ // at least one operand is a key
+ // May still need to fetch the value (if
+ // one of the operands is a value field or a function).
+ if query_checker.ContainsFunctionOperand(e) || query_checker.ContainsValueFieldOperand(e) {
+ return FETCH_VALUE
+ } else if evalComparisonOperators(db, k, nil, e) {
return INCLUDE
} else {
return EXCLUDE
diff --git a/v23/syncbase/nosql/internal/query/query.go b/v23/syncbase/nosql/internal/query/query.go
index ffbd841..bcf525f 100644
--- a/v23/syncbase/nosql/internal/query/query.go
+++ b/v23/syncbase/nosql/internal/query/query.go
@@ -48,7 +48,7 @@
switch selector.Type {
case query_parser.TypSelField:
// If field not found, nil is returned (as per specification).
- f, _, _ := ResolveField(db, k, v, selector.Field)
+ f := ResolveField(db, k, v, selector.Field)
projection = append(projection, f)
case query_parser.TypSelFunc:
if selector.Function.Computed {
diff --git a/v23/syncbase/nosql/internal/query/query_checker/query_checker.go b/v23/syncbase/nosql/internal/query/query_checker/query_checker.go
index ef112c3..5927845 100644
--- a/v23/syncbase/nosql/internal/query/query_checker/query_checker.go
+++ b/v23/syncbase/nosql/internal/query/query_checker/query_checker.go
@@ -57,7 +57,7 @@
for _, selector := range s.Selectors {
switch selector.Type {
case query_parser.TypSelField:
- switch selector.Field.Segments[0].Value {
+ switch strings.ToLower(selector.Field.Segments[0].Value) {
case "k":
if len(selector.Field.Segments) > 1 {
return syncql.NewErrDotNotationDisallowedForKey(db.GetContext(), selector.Field.Segments[1].Off)
@@ -135,9 +135,9 @@
e.Operand2.CompRegex = compRegex
}
- // Is/IsNot expressions require operand1 to be a value and operand2 to be nil.
+ // Is/IsNot expressions require operand1 to be a (value or function) and operand2 to be nil.
if e.Operator.Type == query_parser.Is || e.Operator.Type == query_parser.IsNot {
- if !IsField(e.Operand1) {
+ if !IsField(e.Operand1) && !IsFunction(e.Operand1) {
return syncql.NewErrIsIsNotRequireLhsValue(db.GetContext(), e.Operand1.Off)
}
if e.Operand2.Type != query_parser.TypNil {
@@ -145,24 +145,15 @@
}
}
- // type as an operand must be the first operand, the operator must be = and the 2nd operand must be string literal.
- if (IsType(e.Operand1) && (e.Operator.Type != query_parser.Equal || e.Operand2.Type != query_parser.TypStr)) || IsType(e.Operand2) {
- return syncql.NewErrTypeExpressionForm(db.GetContext(), e.Off)
- }
-
- // k as an operand must be the first operand, the operator must be
- // = | <> | > | >= | < | <= | like | not like and the 2nd operand must be a string literal.
- if (IsKey(e.Operand1) &&
- ((e.Operator.Type != query_parser.Equal &&
- e.Operator.Type != query_parser.GreaterThan &&
- e.Operator.Type != query_parser.GreaterThanOrEqual &&
- e.Operator.Type != query_parser.LessThan &&
- e.Operator.Type != query_parser.LessThanOrEqual &&
- e.Operator.Type != query_parser.Like &&
- e.Operator.Type != query_parser.NotEqual &&
- e.Operator.Type != query_parser.NotLike) ||
- e.Operand2.Type != query_parser.TypStr)) || IsKey(e.Operand2) {
- return syncql.NewErrKeyExpressionForm(db.GetContext(), e.Off)
+ // if an operand is k and the other operand is a literal, that literal must be a string
+ // literal.
+ if ContainsKeyOperand(e) && ((isLiteral(e.Operand1) && !isStringLiteral(e.Operand1)) ||
+ (isLiteral(e.Operand2) && !isStringLiteral(e.Operand2))) {
+ off := e.Operand1.Off
+ if isLiteral(e.Operand2) {
+ off = e.Operand2.Off
+ }
+ return syncql.NewErrKeyExpressionLiteral(db.GetContext(), off)
}
// If either operand is a bool, only = and <> operators are allowed.
@@ -178,16 +169,12 @@
case query_parser.TypExpr:
return checkExpression(db, o.Expr)
case query_parser.TypField:
- switch o.Column.Segments[0].Value {
+ switch strings.ToLower(o.Column.Segments[0].Value) {
case "k":
if len(o.Column.Segments) > 1 {
return syncql.NewErrDotNotationDisallowedForKey(db.GetContext(), o.Column.Segments[1].Off)
}
case "v":
- case "t":
- if len(o.Column.Segments) > 1 {
- return syncql.NewErrDotNotationDisallowedForType(db.GetContext(), o.Column.Segments[1].Off)
- }
default:
return syncql.NewErrBadFieldInWhere(db.GetContext(), o.Column.Segments[0].Off)
}
@@ -346,12 +333,42 @@
return o.Type == query_parser.TypField
}
-func IsKey(o *query_parser.Operand) bool {
- return IsField(o) && IsKeyField(o.Column)
+func IsFunction(o *query_parser.Operand) bool {
+ return o.Type == query_parser.TypFunction
}
-func IsType(o *query_parser.Operand) bool {
- return IsField(o) && IsTypeField(o.Column)
+func ContainsKeyOperand(expr *query_parser.Expression) bool {
+ return IsKey(expr.Operand1) || IsKey(expr.Operand2)
+}
+
+func ContainsFunctionOperand(expr *query_parser.Expression) bool {
+ return IsFunction(expr.Operand1) || IsFunction(expr.Operand2)
+}
+
+func ContainsValueFieldOperand(expr *query_parser.Expression) bool {
+ return (expr.Operand1.Type == query_parser.TypField && IsValueField(expr.Operand1.Column)) ||
+ (expr.Operand2.Type == query_parser.TypField && IsValueField(expr.Operand2.Column))
+
+}
+
+func isStringLiteral(o *query_parser.Operand) bool {
+ return o.Type == query_parser.TypStr
+}
+
+func isLiteral(o *query_parser.Operand) bool {
+ return o.Type == query_parser.TypBigInt ||
+ o.Type == query_parser.TypBigRat || // currently, no way to specify as literal
+ o.Type == query_parser.TypBool ||
+ o.Type == query_parser.TypComplex || // currently, no way to specify as literal ||
+ o.Type == query_parser.TypFloat ||
+ o.Type == query_parser.TypInt ||
+ o.Type == query_parser.TypStr ||
+ o.Type == query_parser.TypTime || // currently, no way to specify as literal
+ o.Type == query_parser.TypUint
+}
+
+func IsKey(o *query_parser.Operand) bool {
+ return IsField(o) && IsKeyField(o.Column)
}
func IsKeyField(f *query_parser.Field) bool {
@@ -362,10 +379,6 @@
return strings.ToLower(f.Segments[0].Value) == "v"
}
-func IsTypeField(f *query_parser.Field) bool {
- return strings.ToLower(f.Segments[0].Value) == "t"
-}
-
func IsExpr(o *query_parser.Operand) bool {
return o.Type == query_parser.TypExpr
}
@@ -476,27 +489,70 @@
}
return lhsKeyRanges
}
- } else if IsKey(expr.Operand1) {
- switch expr.Operator.Type {
- case query_parser.Equal:
- return &query_db.KeyRanges{computeKeyRangeForSingleValue(expr.Operand2.Str)}
- case query_parser.GreaterThan:
- return &query_db.KeyRanges{query_db.KeyRange{string(append([]byte(expr.Operand2.Str), 0)), MaxRangeLimit}}
- case query_parser.GreaterThanOrEqual:
- return &query_db.KeyRanges{query_db.KeyRange{expr.Operand2.Str, MaxRangeLimit}}
- case query_parser.Like:
- return &query_db.KeyRanges{computeKeyRangeForLike(expr.Operand2.Prefix)}
- case query_parser.NotLike:
- return computeKeyRangesForNotLike(expr.Operand2.Prefix)
- case query_parser.LessThan:
- return &query_db.KeyRanges{query_db.KeyRange{"", expr.Operand2.Str}}
- case query_parser.LessThanOrEqual:
- return &query_db.KeyRanges{query_db.KeyRange{"", string(append([]byte(expr.Operand2.Str), 0))}}
- default: // case query_parser.NotEqual:
- return &query_db.KeyRanges{
- query_db.KeyRange{"", expr.Operand2.Str},
- query_db.KeyRange{string(append([]byte(expr.Operand2.Str), 0)), MaxRangeLimit},
+ } else if ContainsKeyOperand(expr) { // true if either operand is 'k'
+ if IsKey(expr.Operand1) && IsKey(expr.Operand2) {
+ //k <op> k
+ switch expr.Operator.Type {
+ case query_parser.Equal, query_parser.GreaterThanOrEqual, query_parser.LessThanOrEqual:
+ // True for all keys
+ return &query_db.KeyRanges{KeyRangeAll}
+ default: // query_parser.NotEqual, query_parser.GreaterThan, query_parser.LessThan:
+ // False for all keys
+ return &query_db.KeyRanges{}
}
+ } else if expr.Operator.Type == query_parser.Is {
+ // k is nil
+ // False for all keys
+ return &query_db.KeyRanges{}
+ } else if expr.Operator.Type == query_parser.IsNot {
+ // k is not nil
+ // True for all keys
+ return &query_db.KeyRanges{KeyRangeAll}
+ } else if isStringLiteral(expr.Operand2) {
+ // k <op> <string-literal>
+ switch expr.Operator.Type {
+ case query_parser.Equal:
+ return &query_db.KeyRanges{computeKeyRangeForSingleValue(expr.Operand2.Str)}
+ case query_parser.GreaterThan:
+ return &query_db.KeyRanges{query_db.KeyRange{string(append([]byte(expr.Operand2.Str), 0)), MaxRangeLimit}}
+ case query_parser.GreaterThanOrEqual:
+ return &query_db.KeyRanges{query_db.KeyRange{expr.Operand2.Str, MaxRangeLimit}}
+ case query_parser.Like:
+ return &query_db.KeyRanges{computeKeyRangeForLike(expr.Operand2.Prefix)}
+ case query_parser.NotLike:
+ return computeKeyRangesForNotLike(expr.Operand2.Prefix)
+ case query_parser.LessThan:
+ return &query_db.KeyRanges{query_db.KeyRange{"", expr.Operand2.Str}}
+ case query_parser.LessThanOrEqual:
+ return &query_db.KeyRanges{query_db.KeyRange{"", string(append([]byte(expr.Operand2.Str), 0))}}
+ default: // case query_parser.NotEqual:
+ return &query_db.KeyRanges{
+ query_db.KeyRange{"", expr.Operand2.Str},
+ query_db.KeyRange{string(append([]byte(expr.Operand2.Str), 0)), MaxRangeLimit},
+ }
+ }
+ } else if isStringLiteral(expr.Operand1) {
+ //<string-literal> <op> k
+ switch expr.Operator.Type {
+ case query_parser.Equal:
+ return &query_db.KeyRanges{computeKeyRangeForSingleValue(expr.Operand1.Str)}
+ case query_parser.GreaterThan:
+ return &query_db.KeyRanges{query_db.KeyRange{"", expr.Operand1.Str}}
+ case query_parser.GreaterThanOrEqual:
+ return &query_db.KeyRanges{query_db.KeyRange{"", string(append([]byte(expr.Operand1.Str), 0))}}
+ case query_parser.LessThan:
+ return &query_db.KeyRanges{query_db.KeyRange{string(append([]byte(expr.Operand1.Str), 0)), MaxRangeLimit}}
+ case query_parser.LessThanOrEqual:
+ return &query_db.KeyRanges{query_db.KeyRange{expr.Operand1.Str, MaxRangeLimit}}
+ default: // case query_parser.NotEqual:
+ return &query_db.KeyRanges{
+ query_db.KeyRange{"", expr.Operand1.Str},
+ query_db.KeyRange{string(append([]byte(expr.Operand1.Str), 0)), MaxRangeLimit},
+ }
+ }
+ } else {
+ // A function or a field s being compared to the key.
+ return &query_db.KeyRanges{KeyRangeAll}
}
} else { // not a key compare, so it applies to the entire key range
return &query_db.KeyRanges{KeyRangeAll}
diff --git a/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go b/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go
index dc7fa12..9d410b0 100644
--- a/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go
+++ b/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go
@@ -90,8 +90,50 @@
{"select k, v.name from Customer limit 200"},
{"select k, v.name from Customer offset 100"},
{"select k, v.name from Customer where k = \"foo\""},
- {"select v from Customer where t = \"Foo.Bar\""},
- {"select k, v from Customer where t = \"Foo.Bar\" and k like \"abc%\" limit 100 offset 200"},
+ {"select v.z from Customer where k = v.y"},
+ {"select v.z from Customer where k <> v.y"},
+ {"select v.z from Customer where k < v.y"},
+ {"select v.z from Customer where k <= v.y"},
+ {"select v.z from Customer where k > v.y"},
+ {"select v.z from Customer where k >= v.y"},
+ {"select v from Customer where k is nil"},
+ {"select v from Customer where k is not nil"},
+ {"select k, v.name from Customer where \"foo\" = k"},
+ {"select v.z from Customer where v.y = k"},
+ {"select v.z from Customer where v.y <> k"},
+ {"select v.z from Customer where v.y < k"},
+ {"select v.z from Customer where v.y <= k"},
+ {"select v.z from Customer where v.y > k"},
+ {"select v.z from Customer where v.y >= k"},
+ {"select v.z from Customer where \"abc%\" = k"},
+ {"select v from Customer where k is nil"},
+ {"select v from Customer where k is not nil"},
+ {"select v from Customer where Type(v) = \"Foo.Bar\""},
+ {"select v from Customer where Type(v) <> \"Foo.Bar\""},
+ {"select v from Customer where Type(v) < \"Foo.Bar\""},
+ {"select v from Customer where Type(v) <= \"Foo.Bar\""},
+ {"select v from Customer where Type(v) > \"Foo.Bar\""},
+ {"select v from Customer where Type(v) >= \"Foo.Bar\""},
+ {"select v from Customer where Type(v) like \"%.Foo.Bar\""},
+ {"select v from Customer where Type(v) not like \"%.Foo.Bar\""},
+ {"select v from Customer where Type(v) is nil"},
+ {"select v from Customer where Type(v) is not nil"},
+ {"select v from Customer where \"Foo.Bar\" = Type(v)"},
+ {"select v from Customer where \"Foo.Bar\" <> Type(v)"},
+ {"select v from Customer where \"Foo.Bar\" < Type(v)"},
+ {"select v from Customer where \"Foo.Bar\" > Type(v)"},
+ {"select v from Customer where \"Foo.Bar\" <= Type(v)"},
+ {"select v from Customer where \"Foo.Bar\" >= Type(v)"},
+ {"select v.z from Customer where Type(v) = 2"},
+ {"select v.z from Customer where Type(v) <> \"foo\""},
+ {"select v.z from Customer where Type(v) < \"foo\""},
+ {"select v.z from Customer where Type(v) <= \"foo\""},
+ {"select v.z from Customer where Type(v) > \"foo\""},
+ {"select v.z from Customer where Type(v) >= \"foo\""},
+ {"select v.z from Customer where \"foo\" = Type(v)"},
+ {"select k, v from Customer where Type(v) = \"Foo.Bar\" and k like \"abc%\" limit 100 offset 200"},
+ {"select v from Customer where Type(v) is nil"},
+ {"select v from Customer where Type(v) is not nil"},
{"select v.z from Customer where k not like \"foo\""},
{"select v.z from Customer where k not like \"foo%\""},
{"select v from Customer where v.A = true"},
@@ -146,13 +188,20 @@
},
},
{
+ "select k, v from Customer where \"abc\" = k or \"def\" = k",
+ &query_db.KeyRanges{
+ query_db.KeyRange{"abc", appendZeroByte("abc")},
+ query_db.KeyRange{"def", appendZeroByte("def")},
+ },
+ },
+ {
"select k, v from Customer where k >= \"foo\" and k < \"goo\"",
&query_db.KeyRanges{
query_db.KeyRange{"foo", "goo"},
},
},
{
- "select k, v from Customer where k >= \"foo\" and k <= \"goo\"",
+ "select k, v from Customer where \"foo\" <= k and \"goo\" >= k",
&query_db.KeyRanges{
query_db.KeyRange{"foo", appendZeroByte("goo")},
},
@@ -185,7 +234,7 @@
},
},
{
- "select v from Customer where t = \"Foo.Bar\" and k >= \"100\" and k < \"200\" and v.foo > 50 and v.bar <= 1000 and v.baz <> -20.7",
+ "select v from Customer where Type(v) = \"Foo.Bar\" and k >= \"100\" and k < \"200\" and v.foo > 50 and v.bar <= 1000 and v.baz <> -20.7",
&query_db.KeyRanges{
query_db.KeyRange{"100", "200"},
},
@@ -195,7 +244,7 @@
&query_db.KeyRanges{},
},
{
- "select k, v from Customer where t = \"Foo.Bar\" and k like \"abc%\" limit 100 offset 200",
+ "select k, v from Customer where Type(v) = \"Foo.Bar\" and k like \"abc%\" limit 100 offset 200",
&query_db.KeyRanges{
query_db.KeyRange{"abc", "abd"},
},
@@ -365,53 +414,35 @@
{"select a from Customer", syncql.NewErrInvalidSelectField(db.GetContext(), 7)},
{"select v from Bob", syncql.NewErrTableCantAccess(db.GetContext(), 14, "Bob", errors.New("No such table: Bob"))},
{"select k.a from Customer", syncql.NewErrDotNotationDisallowedForKey(db.GetContext(), 9)},
- {"select k from Customer where t.a = \"Foo.Bar\"", syncql.NewErrDotNotationDisallowedForType(db.GetContext(), 31)},
+ {"select k from Customer where t.a = \"Foo.Bar\"", syncql.NewErrBadFieldInWhere(db.GetContext(), 29)},
{"select v from Customer where a=1", syncql.NewErrBadFieldInWhere(db.GetContext(), 29)},
{"select v from Customer limit 0", syncql.NewErrLimitMustBeGe0(db.GetContext(), 29)},
- {"select v.z from Customer where t = 2", syncql.NewErrTypeExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where t <> \"foo\"", syncql.NewErrTypeExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where t < \"foo\"", syncql.NewErrTypeExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where t <= \"foo\"", syncql.NewErrTypeExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where t > \"foo\"", syncql.NewErrTypeExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where t >= \"foo\"", syncql.NewErrTypeExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where \"foo\" = t", syncql.NewErrTypeExpressionForm(db.GetContext(), 31)},
{"select v.z from Customer where v.x like v.y", syncql.NewErrLikeExpressionsRequireRhsString(db.GetContext(), 31)},
- {"select v.z from Customer where k = v.y", syncql.NewErrKeyExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where k <> v.y", syncql.NewErrKeyExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where k < v.y", syncql.NewErrKeyExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where k <= v.y", syncql.NewErrKeyExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where k > v.y", syncql.NewErrKeyExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where k >= v.y", syncql.NewErrKeyExpressionForm(db.GetContext(), 31)},
- {"select v.z from Customer where \"abc%\" = k", syncql.NewErrKeyExpressionForm(db.GetContext(), 31)},
{"select v.z from Customer where k like \"a\\bc%\"", syncql.NewErrInvalidEscapedChar(db.GetContext(), 38)},
{"select v from Customer where v.A > false", syncql.NewErrBoolInvalidExpression(db.GetContext(), 33)},
{"select v from Customer where true <= v.A", syncql.NewErrBoolInvalidExpression(db.GetContext(), 34)},
{"select v from Customer where Foo(\"2015/07/22\", true, 3.14157) = true", syncql.NewErrFunctionNotFound(db.GetContext(), 29, "Foo")},
- {"select v from Customer where t is nil", syncql.NewErrTypeExpressionForm(db.GetContext(), 29)},
- {"select v from Customer where k is nil", syncql.NewErrKeyExpressionForm(db.GetContext(), 29)},
{"select v from Customer where nil is v.ZipCode", syncql.NewErrIsIsNotRequireLhsValue(db.GetContext(), 29)},
{"select v from Customer where v.ZipCode is \"94303\"", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 42)},
{"select v from Customer where v.ZipCode is 94303", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 42)},
{"select v from Customer where v.ZipCode is true", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 42)},
{"select v from Customer where v.ZipCode is 943.03", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 42)},
- {"select v from Customer where t is not nil", syncql.NewErrTypeExpressionForm(db.GetContext(), 29)},
- {"select v from Customer where k is not nil", syncql.NewErrKeyExpressionForm(db.GetContext(), 29)},
{"select v from Customer where nil is not v.ZipCode", syncql.NewErrIsIsNotRequireLhsValue(db.GetContext(), 29)},
{"select v from Customer where v.ZipCode is not \"94303\"", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 46)},
{"select v from Customer where v.ZipCode is not 94303", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 46)},
{"select v from Customer where v.ZipCode is not true", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 46)},
{"select v from Customer where v.ZipCode is not 943.03", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 46)},
- {"select v from Customer where t = \"Customer\" and y(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionReturnedError(db.GetContext(), 65, "y", errors.New("unknown time zone ABC"))},
- {"select v from Customer where t = \"Customer\" and YM(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionReturnedError(db.GetContext(), 66, "YM", errors.New("unknown time zone ABC"))},
- {"select v from Customer where t = \"Customer\" and YMD(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionReturnedError(db.GetContext(), 67, "YMD", errors.New("unknown time zone ABC"))},
- {"select v from Customer where t = \"Customer\" and YMDH(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionReturnedError(db.GetContext(), 68, "YMDH", errors.New("unknown time zone ABC"))},
- {"select v from Customer where t = \"Customer\" and YMDHM(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionReturnedError(db.GetContext(), 69, "YMDHM", errors.New("unknown time zone ABC"))},
- {"select v from Customer where t = \"Customer\" and YMDHMS(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionReturnedError(db.GetContext(), 70, "YMDHMS", errors.New("unknown time zone ABC"))},
- {"select v from Customer where t = \"Customer\" and Now(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionArgCount(db.GetContext(), 48, "Now", 0, 2)},
- {"select v from Customer where t = \"Customer\" and LowerCase(v.Name, 2) = \"smith\"", syncql.NewErrFunctionArgCount(db.GetContext(), 48, "LowerCase", 1, 2)},
- {"select v from Customer where t = \"Customer\" and UpperCase(v.Name, 2) = \"SMITH\"", syncql.NewErrFunctionArgCount(db.GetContext(), 48, "UpperCase", 1, 2)},
+ {"select v from Customer where Type(v) = \"Customer\" and y(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 71, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and YM(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 72, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and YMD(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 73, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and YMDH(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 74, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and YMDHM(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 75, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and YMDHMS(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 76, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and Now(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionArgCount(db.GetContext(), 54, "Now", 0, 2)},
+ {"select v from Customer where Type(v) = \"Customer\" and LowerCase(v.Name, 2) = \"smith\"", syncql.NewErrFunctionArgCount(db.GetContext(), 54, "LowerCase", 1, 2)},
+ {"select v from Customer where Type(v) = \"Customer\" and UpperCase(v.Name, 2) = \"SMITH\"", syncql.NewErrFunctionArgCount(db.GetContext(), 54, "UpperCase", 1, 2)},
{"select Date() from Customer", syncql.NewErrFunctionArgCount(db.GetContext(), 7, "Date", 1, 0)},
- {"select Y(v.InvoiceDate, \"Foo\") from Customer where t = \"Invoice\"", syncql.NewErrFunctionReturnedError(db.GetContext(), 24, "Y", errors.New("unknown time zone Foo"))},
+ {"select Y(v.InvoiceDate, \"Foo\") from Customer where Type(v) = \"Invoice\"", syncql.NewErrLocationConversionError(db.GetContext(), 24, errors.New("unknown time zone Foo"))},
}
for _, test := range basic {
diff --git a/v23/syncbase/nosql/internal/query/query_functions/date_funcs.go b/v23/syncbase/nosql/internal/query/query_functions/date_funcs.go
index 74dc7f2..1a1ed91 100644
--- a/v23/syncbase/nosql/internal/query/query_functions/date_funcs.go
+++ b/v23/syncbase/nosql/internal/query/query_functions/date_funcs.go
@@ -9,21 +9,31 @@
"v.io/syncbase/v23/syncbase/nosql/internal/query/conversions"
"v.io/syncbase/v23/syncbase/nosql/internal/query/query_parser"
+ "v.io/syncbase/v23/syncbase/nosql/query_db"
+ "v.io/syncbase/v23/syncbase/nosql/syncql"
)
// If possible, check if arg is convertable to a time. Fields and not yet computed
// functions cannot be checked and will just return nil.
-func checkIfPossibleThatArgIsConvertableToTime(arg *query_parser.Operand) error {
+func checkIfPossibleThatArgIsConvertableToTime(db query_db.Database, arg *query_parser.Operand) error {
// If arg is a literal or an already computed function,
// make sure it can be converted to a time.
switch arg.Type {
case query_parser.TypBigInt, query_parser.TypBigRat, query_parser.TypBool, query_parser.TypComplex, query_parser.TypFloat, query_parser.TypInt, query_parser.TypStr, query_parser.TypTime, query_parser.TypUint:
_, err := conversions.ConvertValueToTime(arg)
- return err
+ if err != nil {
+ return syncql.NewErrTimeConversionError(db.GetContext(), arg.Off, err)
+ } else {
+ return nil
+ }
case query_parser.TypFunction:
if arg.Function.Computed {
_, err := conversions.ConvertValueToTime(arg.Function.RetValue)
- return err
+ if err != nil {
+ return syncql.NewErrTimeConversionError(db.GetContext(), arg.Off, err)
+ } else {
+ return nil
+ }
}
}
return nil
@@ -31,18 +41,26 @@
// If possible, check if arg is convertable to a location. Fields and not yet computed
// functions cannot be checked and will just return nil.
-func checkIfPossibleThatArgIsConvertableToLocation(arg *query_parser.Operand) error {
+func checkIfPossibleThatArgIsConvertableToLocation(db query_db.Database, arg *query_parser.Operand) error {
var locStr *query_parser.Operand
var err error
switch arg.Type {
case query_parser.TypBigInt, query_parser.TypBigRat, query_parser.TypBool, query_parser.TypComplex, query_parser.TypFloat, query_parser.TypInt, query_parser.TypStr, query_parser.TypTime, query_parser.TypUint:
if locStr, err = conversions.ConvertValueToString(arg); err != nil {
- return err
+ if err != nil {
+ return syncql.NewErrLocationConversionError(db.GetContext(), arg.Off, err)
+ } else {
+ return nil
+ }
}
case query_parser.TypFunction:
if arg.Function.Computed {
if locStr, err = conversions.ConvertValueToString(arg.Function.RetValue); err != nil {
- return err
+ if err != nil {
+ return syncql.NewErrLocationConversionError(db.GetContext(), arg.Off, err)
+ } else {
+ return nil
+ }
}
} else {
// Arg is uncomputed function, can't make determination about arg.
@@ -53,7 +71,11 @@
return nil
}
_, err = time.LoadLocation(locStr.Str)
- return err
+ if err != nil {
+ return syncql.NewErrLocationConversionError(db.GetContext(), arg.Off, err)
+ } else {
+ return nil
+ }
}
// Input: "YYYY-MM-DD TZ"
@@ -237,18 +259,18 @@
return &o
}
-func timeAndStringArgsCheck(off int64, args []*query_parser.Operand) (*query_parser.Operand, error) {
+func timeAndStringArgsCheck(db query_db.Database, off int64, args []*query_parser.Operand) error {
// The first arg must be a time.
- if err := checkIfPossibleThatArgIsConvertableToTime(args[0]); err != nil {
- return args[0], err
+ if err := checkIfPossibleThatArgIsConvertableToTime(db, args[0]); err != nil {
+ return err
}
// The second arg must be a string and convertable to a location.
- if err := checkIfPossibleThatArgIsConvertableToLocation(args[1]); err != nil {
- return args[1], err
+ if err := checkIfPossibleThatArgIsConvertableToLocation(db, args[1]); err != nil {
+ return err
}
- return nil, nil
+ return nil
}
-func singleTimeArgCheck(off int64, args []*query_parser.Operand) (*query_parser.Operand, error) {
- return checkIfPossibleThatArgIsConvertableToString(args[0])
+func singleTimeArgCheck(db query_db.Database, off int64, args []*query_parser.Operand) error {
+ return checkIfPossibleThatArgIsConvertableToString(db, args[0])
}
diff --git a/v23/syncbase/nosql/internal/query/query_functions/math_funcs.go b/v23/syncbase/nosql/internal/query/query_functions/math_funcs.go
index cfb01ae..5628180 100644
--- a/v23/syncbase/nosql/internal/query/query_functions/math_funcs.go
+++ b/v23/syncbase/nosql/internal/query/query_functions/math_funcs.go
@@ -7,6 +7,8 @@
import (
"v.io/syncbase/v23/syncbase/nosql/internal/query/conversions"
"v.io/syncbase/v23/syncbase/nosql/internal/query/query_parser"
+ "v.io/syncbase/v23/syncbase/nosql/query_db"
+ "v.io/syncbase/v23/syncbase/nosql/syncql"
)
func complexFunc(off int64, args []*query_parser.Operand) (*query_parser.Operand, error) {
@@ -23,15 +25,14 @@
return makeComplexOp(off, complex(r.Float, i.Float)), nil
}
-func twoFloatsArgsCheck(off int64, args []*query_parser.Operand) (*query_parser.Operand, error) {
+func twoFloatsArgsCheck(db query_db.Database, off int64, args []*query_parser.Operand) error {
// The two args must be convertable to floats.
- if err := checkIfPossibleThatArgIsConvertableToFloat(args[0]); err != nil {
- return args[0], err
+ for i := 0; i < 2; i++ {
+ if err := checkIfPossibleThatArgIsConvertableToFloat(args[i]); err != nil {
+ return syncql.NewErrFloatConversionError(db.GetContext(), args[i].Off, err)
+ }
}
- if err := checkIfPossibleThatArgIsConvertableToFloat(args[1]); err != nil {
- return args[1], err
- }
- return nil, nil
+ return nil
}
// If possible, check if arg is convertable to a float. Fields and not yet computed
diff --git a/v23/syncbase/nosql/internal/query/query_functions/query_functions.go b/v23/syncbase/nosql/internal/query/query_functions/query_functions.go
index 326bbf8..285d875 100644
--- a/v23/syncbase/nosql/internal/query/query_functions/query_functions.go
+++ b/v23/syncbase/nosql/internal/query/query_functions/query_functions.go
@@ -15,7 +15,7 @@
)
type queryFunc func(int64, []*query_parser.Operand) (*query_parser.Operand, error)
-type checkArgsFunc func(int64, []*query_parser.Operand) (*query_parser.Operand, error)
+type checkArgsFunc func(query_db.Database, int64, []*query_parser.Operand) error
type function struct {
argTypes []query_parser.OperandType
@@ -40,6 +40,7 @@
functions["now"] = function{[]query_parser.OperandType{}, query_parser.TypTime, now, nil}
functions["lowercase"] = function{[]query_parser.OperandType{query_parser.TypStr}, query_parser.TypStr, lowerCase, singleStringArgCheck}
+ functions["type"] = function{[]query_parser.OperandType{query_parser.TypObject}, query_parser.TypStr, typeFunc, singleFieldArgCheck}
functions["uppercase"] = function{[]query_parser.OperandType{query_parser.TypStr}, query_parser.TypStr, upperCase, singleStringArgCheck}
functions["complex"] = function{[]query_parser.OperandType{query_parser.TypFloat, query_parser.TypFloat}, query_parser.TypComplex, complexFunc, twoFloatsArgsCheck}
@@ -102,8 +103,8 @@
return syncql.NewErrFunctionNotFound(db.GetContext(), f.Off, f.Name)
} else {
if entry.checkArgsAddr != nil {
- if arg, err := entry.checkArgsAddr(f.Off, args); err != nil {
- return syncql.NewErrFunctionReturnedError(db.GetContext(), arg.Off, f.Name, err)
+ if err := entry.checkArgsAddr(db, f.Off, args); err != nil {
+ return err
}
}
}
@@ -116,7 +117,7 @@
} else {
retValue, err := entry.funcAddr(f.Off, args)
if err != nil {
- return nil, syncql.NewErrFunctionReturnedError(db.GetContext(), f.Off, f.Name, err)
+ return nil, err
} else {
return retValue, nil
}
@@ -124,6 +125,9 @@
}
func ConvertFunctionRetValueToVdlValue(o *query_parser.Operand) *vdl.Value {
+ if o == nil {
+ return vdl.ValueOf(nil)
+ }
switch o.Type {
case query_parser.TypBool:
return vdl.ValueOf(o.Bool)
@@ -145,7 +149,7 @@
// Other types can't be converted and *shouldn't* be returned
// from a function. This case will result in a nil for this
// column in the row.
- return nil
+ return vdl.ValueOf(nil)
}
}
@@ -157,6 +161,13 @@
return &o
}
+func makeStrOpWithAlt(off int64, s string, alt string) *query_parser.Operand {
+ o := makeStrOp(off, s)
+ o.HasAltStr = true
+ o.AltStr = alt
+ return o
+}
+
func makeComplexOp(off int64, c complex128) *query_parser.Operand {
var o query_parser.Operand
o.Off = off
@@ -165,24 +176,41 @@
return &o
}
-func singleStringArgCheck(off int64, args []*query_parser.Operand) (*query_parser.Operand, error) {
- return checkIfPossibleThatArgIsConvertableToString(args[0])
+func singleStringArgCheck(db query_db.Database, off int64, args []*query_parser.Operand) error {
+ return checkIfPossibleThatArgIsConvertableToString(db, args[0])
+}
+
+func singleFieldArgCheck(db query_db.Database, off int64, args []*query_parser.Operand) error {
+ // single argument must be of type field
+ // It must begin with a v segment.
+ if args[0].Type != query_parser.TypField || len(args[0].Column.Segments) < 1 || strings.ToLower(args[0].Column.Segments[0].Value) != "v" {
+ return syncql.NewErrArgMustBeField(db.GetContext(), args[0].Off)
+ }
+ return nil
}
// If possible, check if arg is convertable to a string. Fields and not yet computed
// functions cannot be checked and will just return nil.
-func checkIfPossibleThatArgIsConvertableToString(arg *query_parser.Operand) (*query_parser.Operand, error) {
+func checkIfPossibleThatArgIsConvertableToString(db query_db.Database, arg *query_parser.Operand) error {
// If arg is a literal or an already computed function,
// make sure it can be converted to a string.
switch arg.Type {
case query_parser.TypBigInt, query_parser.TypBigRat, query_parser.TypBool, query_parser.TypComplex, query_parser.TypFloat, query_parser.TypInt, query_parser.TypStr, query_parser.TypTime, query_parser.TypUint:
_, err := conversions.ConvertValueToString(arg)
- return arg, err
+ if err != nil {
+ return syncql.NewErrStringConversionError(db.GetContext(), arg.Off, err)
+ } else {
+ return nil
+ }
case query_parser.TypFunction:
if arg.Function.Computed {
_, err := conversions.ConvertValueToString(arg.Function.RetValue)
- return arg, err
+ if err != nil {
+ return syncql.NewErrStringConversionError(db.GetContext(), arg.Off, err)
+ } else {
+ return nil
+ }
}
}
- return nil, nil
+ return nil
}
diff --git a/v23/syncbase/nosql/internal/query/query_functions/str_funcs.go b/v23/syncbase/nosql/internal/query/query_functions/str_funcs.go
index 5a253ee..77b6eac 100644
--- a/v23/syncbase/nosql/internal/query/query_functions/str_funcs.go
+++ b/v23/syncbase/nosql/internal/query/query_functions/str_funcs.go
@@ -5,10 +5,12 @@
package query_functions
import (
+ "errors"
"strings"
"v.io/syncbase/v23/syncbase/nosql/internal/query/conversions"
"v.io/syncbase/v23/syncbase/nosql/internal/query/query_parser"
+ "v.io/v23/vdl"
)
func lowerCase(off int64, args []*query_parser.Operand) (*query_parser.Operand, error) {
@@ -26,3 +28,13 @@
}
return makeStrOp(off, strings.ToUpper(strOp.Str)), nil
}
+
+func typeFunc(off int64, args []*query_parser.Operand) (*query_parser.Operand, error) {
+ // If operand is not an object, we can't get a type
+ if args[0].Type != query_parser.TypObject {
+ return nil, errors.New("Type function argument must be object.")
+ }
+ t := args[0].Object.Type()
+ pkg, name := vdl.SplitIdent(t.Name())
+ return makeStrOpWithAlt(off, pkg+"."+name, name), nil
+}
diff --git a/v23/syncbase/nosql/internal/query/query_parser/doc.go b/v23/syncbase/nosql/internal/query/query_parser/doc.go
index 915ac29..3676075 100644
--- a/v23/syncbase/nosql/internal/query/query_parser/doc.go
+++ b/v23/syncbase/nosql/internal/query/query_parser/doc.go
@@ -58,7 +58,6 @@
// <operand> ::=
// K
// | V[<period><field>]
-// | T
// | <literal>
// | <function>
//
@@ -81,5 +80,5 @@
// | <float_literal>
//
// Example:
-// select v.foo.bar, v.baz[2] from foobarbaz where (v.foo = 42 and v.bar not like "abc%) or (k >= "100" and k < "200")
+// select v.foo.bar, v.baz[2] from foobarbaz where Type(v) = "Customer" and (v.foo = 42 and v.bar not like "abc%) or (k >= "100" and k < "200")
package query_parser
diff --git a/v23/syncbase/nosql/internal/query/test/db_objects.vdl b/v23/syncbase/nosql/internal/query/test/db_objects.vdl
index 487f40e..a35dd1f 100644
--- a/v23/syncbase/nosql/internal/query/test/db_objects.vdl
+++ b/v23/syncbase/nosql/internal/query/test/db_objects.vdl
@@ -158,3 +158,7 @@
S set[string]
T set[time.Time]
}
+
+type BigData struct {
+ Key string // A dup of the key stored in the value.
+}
diff --git a/v23/syncbase/nosql/internal/query/test/db_objects.vdl.go b/v23/syncbase/nosql/internal/query/test/db_objects.vdl.go
index a402510..5584378 100644
--- a/v23/syncbase/nosql/internal/query/test/db_objects.vdl.go
+++ b/v23/syncbase/nosql/internal/query/test/db_objects.vdl.go
@@ -462,6 +462,15 @@
}) {
}
+type BigData struct {
+ Key string // A dup of the key stored in the value.
+}
+
+func (BigData) __VDLReflect(struct {
+ Name string `vdl:"v.io/syncbase/v23/syncbase/nosql/internal/query/test.BigData"`
+}) {
+}
+
func init() {
vdl.Register((*AddressInfo)(nil))
vdl.Register((*CreditAgency)(nil))
@@ -485,4 +494,5 @@
vdl.Register((*FunWithMaps)(nil))
vdl.Register((*ManyMaps)(nil))
vdl.Register((*ManySets)(nil))
+ vdl.Register((*BigData)(nil))
}
diff --git a/v23/syncbase/nosql/internal/query/test/query_test.go b/v23/syncbase/nosql/internal/query/test/query_test.go
index 8f24388..0d4cce7 100644
--- a/v23/syncbase/nosql/internal/query/test/query_test.go
+++ b/v23/syncbase/nosql/internal/query/test/query_test.go
@@ -121,6 +121,7 @@
var previousAddressesTable table
var manyMapsTable table
var manySetsTable table
+var bigTable table
type kv struct {
key string
@@ -374,6 +375,15 @@
},
}
db.tables = append(db.tables, manySetsTable)
+
+ bigTable.name = "BigTable"
+
+ for i := 100; i < 301; i++ {
+ k := fmt.Sprintf("%d", i)
+ b := vdl.ValueOf(BigData{k})
+ bigTable.rows = append(bigTable.rows, kv{k, b})
+ }
+ db.tables = append(db.tables, bigTable)
}
type keyRangesTest struct {
@@ -436,7 +446,7 @@
basic := []execSelectTest{
{
// Select values for all customer records.
- "select v from Customer where t = \"Customer\"",
+ "select v from Customer where Type(v) = \"Customer\"",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{custTable.rows[0].value},
@@ -445,6 +455,96 @@
},
},
{
+ // Select values for all customer records.
+ "select v from Customer where Type(v) not like \"%Customer\"",
+ []string{"v"},
+ [][]*vdl.Value{
+ []*vdl.Value{custTable.rows[1].value},
+ []*vdl.Value{custTable.rows[2].value},
+ []*vdl.Value{custTable.rows[3].value},
+ []*vdl.Value{custTable.rows[5].value},
+ []*vdl.Value{custTable.rows[6].value},
+ []*vdl.Value{custTable.rows[7].value},
+ []*vdl.Value{custTable.rows[8].value},
+ },
+ },
+ {
+ // Select values for all customer records.
+ "select Type(v) from Customer where Type(v) not like \"%Customer\"",
+ []string{"Type"},
+ [][]*vdl.Value{
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ },
+ },
+ {
+ // All customers have a v.Credit with type CreditReport.
+ "select v from Customer where Type(v.Credit) = \"CreditReport\"",
+ []string{"v"},
+ [][]*vdl.Value{
+ []*vdl.Value{custTable.rows[0].value},
+ []*vdl.Value{custTable.rows[4].value},
+ []*vdl.Value{custTable.rows[9].value},
+ },
+ },
+ {
+ // Only customer "001" has an equifax report.
+ "select v from Customer where Type(v.Credit.Report.EquifaxReport) = \"EquifaxCreditReport\"",
+ []string{"v"},
+ [][]*vdl.Value{
+ []*vdl.Value{custTable.rows[0].value},
+ },
+ },
+ {
+ // Print the types of every record
+ "select Type(v) from Customer",
+ []string{"Type"},
+ [][]*vdl.Value{
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Customer")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Customer")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Invoice")},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Customer")},
+ },
+ },
+ {
+ // Print the types of every credit report
+ "select Type(v.Credit.Report) from Customer",
+ []string{"Type"},
+ [][]*vdl.Value{
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.AgencyReport")},
+ []*vdl.Value{vdl.ValueOf(nil)},
+ []*vdl.Value{vdl.ValueOf(nil)},
+ []*vdl.Value{vdl.ValueOf(nil)},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.AgencyReport")},
+ []*vdl.Value{vdl.ValueOf(nil)},
+ []*vdl.Value{vdl.ValueOf(nil)},
+ []*vdl.Value{vdl.ValueOf(nil)},
+ []*vdl.Value{vdl.ValueOf(nil)},
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.AgencyReport")},
+ },
+ },
+ {
+ // Print the types of every cusomer's v.Credit.Report.EquifaxReport
+ "select Type(v.Credit.Report.EquifaxReport) from Customer where Type(v) = \"Customer\"",
+ []string{"Type"},
+ [][]*vdl.Value{
+ []*vdl.Value{vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.EquifaxCreditReport")},
+ []*vdl.Value{vdl.ValueOf(vdl.ValueOf(nil))},
+ []*vdl.Value{vdl.ValueOf(vdl.ValueOf(nil))},
+ },
+ },
+ {
// Select values where v.InvoiceNum is nil
// Since InvoiceNum does not exist for Invoice,
// this will return just customers.
@@ -536,7 +636,7 @@
},
{
// Select keys & values for all customer records.
- "select k, v from Customer where t = \"Customer\"",
+ "select k, v from Customer where \"Customer\" = Type(v)",
[]string{"k", "v"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(custTable.rows[0].key), custTable.rows[0].value},
@@ -546,7 +646,7 @@
},
{
// Select keys & names for all customer records.
- "select k, v.Name from Customer where t = \"Customer\"",
+ "select k, v.Name from Customer where Type(v) = \"Customer\"",
[]string{"k", "v.Name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(custTable.rows[0].key), vdl.ValueOf("John Smith")},
@@ -575,7 +675,7 @@
},
{
// Select keys & values fo all invoice records.
- "select k, v from Customer where t = \"Invoice\"",
+ "select k, v from Customer where Type(v) = \"Invoice\"",
[]string{"k", "v"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(custTable.rows[1].key), custTable.rows[1].value},
@@ -589,7 +689,7 @@
},
{
// Select key, cust id, invoice number and amount for $88 invoices.
- "select k, v.CustId as ID, v.InvoiceNum as InvoiceNumber, v.Amount as Amt from Customer where t = \"Invoice\" and v.Amount = 88",
+ "select k, v.CustId as ID, v.InvoiceNum as InvoiceNumber, v.Amount as Amt from Customer where Type(v) = \"Invoice\" and v.Amount = 88",
[]string{"k", "ID", "InvoiceNumber", "Amt"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(custTable.rows[3].key), vdl.ValueOf(int64(1)), vdl.ValueOf(int64(1005)), vdl.ValueOf(int64(88))},
@@ -717,7 +817,7 @@
},
{
// Select id, name for customers whose last name is Masterson.
- "select v.Id as ID, v.Name as Name from Customer where t = \"Customer\" and v.Name like \"%Masterson\"",
+ "select v.Id as ID, v.Name as Name from Customer where Type(v) = \"Customer\" and v.Name like \"%Masterson\"",
[]string{"ID", "Name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(int64(2)), vdl.ValueOf("Bat Masterson")},
@@ -725,7 +825,7 @@
},
{
// Select records where v.Address.City is "Collins" or type is Invoice.
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\"",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\"",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{custTable.rows[1].value},
@@ -844,7 +944,7 @@
},
{
// Select customer name for customer Id (i.e., key) "001".
- "select v.Name as Name from Customer where t = \"Customer\" and k = \"001\"",
+ "select v.Name as Name from Customer where Type(v) = \"Customer\" and k = \"001\"",
[]string{"Name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("John Smith")},
@@ -893,7 +993,7 @@
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Limit 3
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" limit 3",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" limit 3",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{custTable.rows[1].value},
@@ -904,7 +1004,7 @@
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Offset 5
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" offset 5",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" offset 5",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{custTable.rows[6].value},
@@ -921,21 +1021,21 @@
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Offset 8
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" offset 8",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" offset 8",
[]string{"v"},
[][]*vdl.Value{},
},
{
// Select records where v.Address.City = "Collins" or type is Invoice.
// Offset 23
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" offset 23",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" offset 23",
[]string{"v"},
[][]*vdl.Value{},
},
{
// Select records where v.Address.City = "Collins" is 84 or type is Invoice.
// Limit 3 Offset 2
- "select v from Customer where v.Address.City = \"Collins\" or t = \"Invoice\" limit 3 offset 2",
+ "select v from Customer where v.Address.City = \"Collins\" or Type(v) = \"Invoice\" limit 3 offset 2",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{custTable.rows[3].value},
@@ -946,7 +1046,7 @@
{
// Select records where v.Address.City = "Collins" or (type is Invoice and v.InvoiceNum is not nil).
// Limit 3 Offset 2
- "select v from Customer where v.Address.City = \"Collins\" or (t = \"Invoice\" and v.InvoiceNum is not nil) limit 3 offset 2",
+ "select v from Customer where v.Address.City = \"Collins\" or (Type(v) = \"Invoice\" and v.InvoiceNum is not nil) limit 3 offset 2",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{custTable.rows[3].value},
@@ -957,14 +1057,14 @@
{
// Select records where v.Address.City = "Collins" or (type is Invoice and v.InvoiceNum is nil).
// Limit 3 Offset 2
- "select v from Customer where v.Address.City = \"Collins\" or (t = \"Invoice\" and v.InvoiceNum is nil) limit 3 offset 2",
+ "select v from Customer where v.Address.City = \"Collins\" or (Type(v) = \"Invoice\" and v.InvoiceNum is nil) limit 3 offset 2",
[]string{"v"},
[][]*vdl.Value{},
},
// Test functions.
{
// Select invoice records where date is 2015-03-17
- "select v from Customer where t = \"Invoice\" and YMD(v.InvoiceDate, \"America/Los_Angeles\") = Date(\"2015-03-17 PDT\")",
+ "select v from Customer where Type(v) = \"Invoice\" and YMD(v.InvoiceDate, \"America/Los_Angeles\") = Date(\"2015-03-17 PDT\")",
[]string{"v"},
[][]*vdl.Value{
[]*vdl.Value{custTable.rows[5].value},
@@ -1060,7 +1160,7 @@
// Test string functions in where clause.
{
// Select invoices shipped to Any street -- using LowerCase.
- "select k from Customer where t = \"Invoice\" and LowerCase(v.ShipTo.Street) like \"%any%\"",
+ "select k from Customer where Type(v) = \"Invoice\" and LowerCase(v.ShipTo.Street) like \"%any%\"",
[]string{"k"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(custTable.rows[5].key)},
@@ -1071,7 +1171,7 @@
},
{
// Select invoices shipped to Any street -- using UpperCase.
- "select k from Customer where t = \"Invoice\" and UpperCase(v.ShipTo.Street) like \"%ANY%\"",
+ "select k from Customer where Type(v) = \"Invoice\" and UpperCase(v.ShipTo.Street) like \"%ANY%\"",
[]string{"k"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(custTable.rows[5].key)},
@@ -1117,7 +1217,7 @@
},
// LowerCase function
{
- "select LowerCase(v.Name) as name from Customer where t = \"Customer\"",
+ "select LowerCase(v.Name) as name from Customer where Type(v) = \"Customer\"",
[]string{"name"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("john smith")},
@@ -1127,7 +1227,7 @@
},
// UpperCase function
{
- "select UpperCase(v.Name) as NAME from Customer where t = \"Customer\"",
+ "select UpperCase(v.Name) as NAME from Customer where Type(v) = \"Customer\"",
[]string{"NAME"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf("JOHN SMITH")},
@@ -1137,7 +1237,7 @@
},
// YMDHMS function
{
- "select k, YMDHMS(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMDHMS(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMDHMS",
@@ -1148,7 +1248,7 @@
},
// YMDHM function
{
- "select k, YMDHM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMDHM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMDHM",
@@ -1159,7 +1259,7 @@
},
// YMDH function
{
- "select k, YMDH(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMDH(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMDH",
@@ -1170,7 +1270,7 @@
},
// YMD function
{
- "select k, YMD(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YMD(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YMD",
@@ -1181,7 +1281,7 @@
},
// YM function
{
- "select k, YM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"002003\"",
+ "select k, YM(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"002003\"",
[]string{
"k",
"YM",
@@ -1192,7 +1292,7 @@
},
// Y function
{
- "select k, Y(v.InvoiceDate, \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"001001\"",
+ "select k, Y(v.InvoiceDate, \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"001001\"",
[]string{
"k",
"Y",
@@ -1203,7 +1303,7 @@
},
// Nested functions
{
- "select Y(YM(YMD(YMDH(YMDHM(YMDHMS(v.InvoiceDate, \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\") from Customer where t = \"Invoice\" and k = \"001001\"",
+ "select Y(YM(YMD(YMDH(YMDHM(YMDHMS(v.InvoiceDate, \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\"), \"America/Los_Angeles\") from Customer where Type(v) = \"Invoice\" and k = \"001001\"",
[]string{"Y"},
[][]*vdl.Value{
[]*vdl.Value{vdl.ValueOf(t2015)},
@@ -1211,7 +1311,7 @@
},
// Bad arg to function. Expression is false.
{
- "select v from Customer where t = \"Invoice\" and YMD(v.InvoiceDate, v.Foo) = v.InvoiceDate",
+ "select v from Customer where Type(v) = \"Invoice\" and YMD(v.InvoiceDate, v.Foo) = v.InvoiceDate",
[]string{"v"},
[][]*vdl.Value{},
},
@@ -1465,6 +1565,318 @@
},
},
},
+ {
+ "select k, v.Key from BigTable where k < \"101\" or k = \"200\" or k like \"300%\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{svPair("100"), svPair("200"), svPair("300")},
+ },
+ {
+ "select k, v.Key from BigTable where \"101\" > k or \"200\" = k or k like \"300%\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{svPair("100"), svPair("200"), svPair("300")},
+ },
+ {
+ "select k, v.Key from BigTable where k is nil",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where k is not nil and \"103\" = v.Key",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{svPair("103")},
+ },
+ {
+ "select k, v.Key from BigTable where k like \"10_\" or k like \"20_\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("100"),
+ svPair("101"),
+ svPair("102"),
+ svPair("103"),
+ svPair("104"),
+ svPair("105"),
+ svPair("106"),
+ svPair("107"),
+ svPair("108"),
+ svPair("109"),
+ svPair("200"),
+ svPair("201"),
+ svPair("202"),
+ svPair("203"),
+ svPair("204"),
+ svPair("205"),
+ svPair("206"),
+ svPair("207"),
+ svPair("208"),
+ svPair("209"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where k like \"_%9\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("109"),
+ svPair("119"),
+ svPair("129"),
+ svPair("139"),
+ svPair("149"),
+ svPair("159"),
+ svPair("169"),
+ svPair("179"),
+ svPair("189"),
+ svPair("199"),
+ svPair("209"),
+ svPair("219"),
+ svPair("229"),
+ svPair("239"),
+ svPair("249"),
+ svPair("259"),
+ svPair("269"),
+ svPair("279"),
+ svPair("289"),
+ svPair("299"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where k like \"__0\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("100"),
+ svPair("110"),
+ svPair("120"),
+ svPair("130"),
+ svPair("140"),
+ svPair("150"),
+ svPair("160"),
+ svPair("170"),
+ svPair("180"),
+ svPair("190"),
+ svPair("200"),
+ svPair("210"),
+ svPair("220"),
+ svPair("230"),
+ svPair("240"),
+ svPair("250"),
+ svPair("260"),
+ svPair("270"),
+ svPair("280"),
+ svPair("290"),
+ svPair("300"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where k like \"10%\" or k like \"20%\" or k like \"30%\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("100"),
+ svPair("101"),
+ svPair("102"),
+ svPair("103"),
+ svPair("104"),
+ svPair("105"),
+ svPair("106"),
+ svPair("107"),
+ svPair("108"),
+ svPair("109"),
+ svPair("200"),
+ svPair("201"),
+ svPair("202"),
+ svPair("203"),
+ svPair("204"),
+ svPair("205"),
+ svPair("206"),
+ svPair("207"),
+ svPair("208"),
+ svPair("209"),
+ svPair("300"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where k like \"1__\" and k like \"_2_\" and k like \"__3\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{svPair("123")},
+ },
+ {
+ "select k, v.Key from BigTable where (k > \"100\" and k < \"103\") or (k > \"205\" and k < \"208\")",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("101"),
+ svPair("102"),
+ svPair("206"),
+ svPair("207"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where ( \"100\" < k and \"103\" > k) or (\"205\" < k and \"208\" > k)",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("101"),
+ svPair("102"),
+ svPair("206"),
+ svPair("207"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where k <= \"100\" or k = \"101\" or k >= \"300\" or (k <> \"299\" and k not like \"300\" and k >= \"298\")",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("100"),
+ svPair("101"),
+ svPair("298"),
+ svPair("300"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where \"100\" >= k or \"101\" = k or \"300\" <= k or (\"299\" <> k and k not like \"300\" and \"298\" <= k)",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("100"),
+ svPair("101"),
+ svPair("298"),
+ svPair("300"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where k like \"1%\" and k like \"%9\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{
+ svPair("109"),
+ svPair("119"),
+ svPair("129"),
+ svPair("139"),
+ svPair("149"),
+ svPair("159"),
+ svPair("169"),
+ svPair("179"),
+ svPair("189"),
+ svPair("199"),
+ },
+ },
+ {
+ "select k, v.Key from BigTable where k like \"3%\" and k like \"30%\" and k like \"300%\"",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{svPair("300")},
+ },
+ {
+ "select k, v.Key from BigTable where \"110\" > k",
+ []string{"k", "v.Key"},
+ svPairs(100, 109),
+ },
+ {
+ "select k, v.Key from BigTable where \"110\" < k and \"205\" > k",
+ []string{"k", "v.Key"},
+ svPairs(111, 204),
+ },
+ {
+ "select k, v.Key from BigTable where \"110\" <= k and \"205\" >= k",
+ []string{"k", "v.Key"},
+ svPairs(110, 205),
+ },
+ {
+ "select k, v.Key from BigTable where k is nil",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where k is not nil",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where k <> k",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where k < k",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where k > k",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where k = k",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where k <= k",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where k >= k",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where k = v.Key",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where v.Key = k",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where V.Key = K",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where k <> v.key",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where v.key <> k",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where k < v.key",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where v.key < k",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where k > v.key",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select k, v.Key from BigTable where v.key > k",
+ []string{"k", "v.Key"},
+ [][]*vdl.Value{},
+ },
+ {
+ "select K, V.Key from BigTable where k >= v.Key",
+ []string{"K", "V.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where v.Key >= k",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select K, V.Key from BigTable where k <= v.Key",
+ []string{"K", "V.Key"},
+ svPairs(100, 300),
+ },
+ {
+ "select k, v.Key from BigTable where v.Key <= k",
+ []string{"k", "v.Key"},
+ svPairs(100, 300),
+ },
}
for _, test := range basic {
@@ -1487,6 +1899,21 @@
}
}
+func svPair(s string) []*vdl.Value {
+ v := vdl.ValueOf(s)
+ return []*vdl.Value{v, v}
+}
+
+// Genearate k,v pairs for start to finish (*INCLUSIVE*)
+func svPairs(start, finish int64) [][]*vdl.Value {
+ retVal := [][]*vdl.Value{}
+ for i := start; i <= finish; i++ {
+ v := vdl.ValueOf(fmt.Sprintf("%d", i))
+ retVal = append(retVal, []*vdl.Value{v, v})
+ }
+ return retVal
+}
+
// Use Now to verify it is "pre" executed such that all the rows
// have the same time.
func TestPreExecFunctions(t *testing.T) {
@@ -1584,7 +2011,7 @@
},
{
// All selected rows will have key prefix of "abc".
- "select k, v from Customer where t = \"Foo.Bar\" and k like \"abc%\"",
+ "select k, v from Customer where Type(v) = \"Foo.Bar\" and k like \"abc%\"",
&query_db.KeyRanges{
query_db.KeyRange{"abc", plusOne("abc")},
},
@@ -1592,7 +2019,7 @@
},
{
// Need all keys
- "select k, v from Customer where t = \"Foo.Bar\" or k like \"abc%\"",
+ "select k, v from Customer where Type(v) = \"Foo.Bar\" or k like \"abc%\"",
&query_db.KeyRanges{
query_db.KeyRange{"", ""},
},
@@ -1608,7 +2035,7 @@
},
{
// All selected rows will have key prefix of "foo".
- "select k, v from Customer where t = \"Foo.Bar\" and k like \"foo_bar\"",
+ "select k, v from Customer where Type(v) = \"Foo.Bar\" and k like \"foo_bar\"",
&query_db.KeyRanges{
query_db.KeyRange{"foo", plusOne("foo")},
},
@@ -1778,7 +2205,7 @@
},
{
// Need value (i.e., its type) to determine if row should be selected.
- "select k, v from Customer where k = \"xyz\" or t = \"foo.Bar\"",
+ "select k, v from Customer where k = \"xyz\" or Type(v) = \"foo.Bar\"",
"wxyz",
query.FETCH_VALUE,
},
@@ -1818,11 +2245,11 @@
func TestEval(t *testing.T) {
basic := []evalTest{
{
- "select k, v from Customer where t = \"v.io/syncbase/v23/syncbase/nosql/internal/query/test.Customer\"",
+ "select k, v from Customer where Type(v) = \"v.io/syncbase/v23/syncbase/nosql/internal/query/test.Customer\"",
custTable.rows[0].key, custTable.rows[0].value, true,
},
{
- "select k, v from Customer where t = \"Customer\"",
+ "select k, v from Customer where Type(v) = \"Customer\"",
numTable.rows[0].key, custTable.rows[0].value, true,
},
{
@@ -2057,7 +2484,7 @@
func TestProjection(t *testing.T) {
basic := []projectionTest{
{
- "select k, v from Customer where t = \"Customer\"",
+ "select k, v from Customer where Type(v) = \"Customer\"",
"123456", custTable.rows[0].value,
[]*vdl.Value{
vdl.ValueOf("123456"),
@@ -2065,7 +2492,7 @@
},
},
{
- "select k, v, v.Name, v.Id, v.Active, v.Credit.Agency, v.Credit.Report.EquifaxReport.Rating, v.Address.Street, v.Address.City, v.Address.State, v.Address.Zip from Customer where t = \"Customer\"",
+ "select k, v, v.Name, v.Id, v.Active, v.Credit.Agency, v.Credit.Report.EquifaxReport.Rating, v.Address.Street, v.Address.City, v.Address.State, v.Address.Zip from Customer where Type(v) = \"Customer\"",
custTable.rows[0].key, custTable.rows[0].value,
[]*vdl.Value{
vdl.ValueOf(custTable.rows[0].key),
@@ -2111,7 +2538,7 @@
func TestExecSelectSingleRow(t *testing.T) {
basic := []execSelectSingleRowTest{
{
- "select k, v from Customer where t = \"Customer\"",
+ "select k, v from Customer where Type(v) = \"Customer\"",
"123456", custTable.rows[0].value,
[]*vdl.Value{
vdl.ValueOf("123456"),
@@ -2119,7 +2546,7 @@
},
},
{
- "select k, v from Customer where t = \"Customer\" and k like \"123%\"",
+ "select k, v from Customer where Type(v) = \"Customer\" and k like \"123%\"",
"123456", custTable.rows[0].value,
[]*vdl.Value{
vdl.ValueOf("123456"),
@@ -2127,12 +2554,12 @@
},
},
{
- "select k, v from Customer where t = \"Invoice\" and k like \"123%\"",
+ "select k, v from Customer where Type(v) = \"Invoice\" and k like \"123%\"",
"123456", custTable.rows[0].value,
[]*vdl.Value{},
},
{
- "select k, v from Customer where t = \"Customer\" and k like \"456%\"",
+ "select k, v from Customer where Type(v) = \"Customer\" and k like \"456%\"",
"123456", custTable.rows[0].value,
[]*vdl.Value{},
},
@@ -2149,7 +2576,7 @@
[]*vdl.Value{},
},
{
- "select k, v, v.Name, v.Id, v.Active, v.Credit.Report.EquifaxReport.Rating, v.Credit.Report.ExperianReport.Rating, v.Credit.Report.TransUnionReport.Rating, v.Address.Street, v.Address.City, v.Address.State, v.Address.Zip from Customer where t = \"Customer\"",
+ "select k, v, v.Name, v.Id, v.Active, v.Credit.Report.EquifaxReport.Rating, v.Credit.Report.ExperianReport.Rating, v.Credit.Report.TransUnionReport.Rating, v.Address.Street, v.Address.City, v.Address.State, v.Address.Zip from Customer where Type(v) = \"Customer\"",
custTable.rows[0].key, custTable.rows[0].value,
[]*vdl.Value{
vdl.ValueOf(custTable.rows[0].key),
@@ -2210,6 +2637,14 @@
// The following error text is dependent on implementation of Database.
syncql.NewErrExpected(db.GetContext(), 30, "positive integer literal"),
},
+ {
+ "select k, v.Key from BigTable where 110 <= k and 205 >= k",
+ syncql.NewErrKeyExpressionLiteral(db.GetContext(), 36),
+ },
+ {
+ "select k, v.Key from BigTable where Type(k) = \"BigData\"",
+ syncql.NewErrArgMustBeField(db.GetContext(), 41),
+ },
}
for _, test := range basic {
@@ -2229,20 +2664,6 @@
query_parser.Field{
Segments: []query_parser.Segment{
query_parser.Segment{
- Value: "t",
- Node: query_parser.Node{Off: 7},
- },
- },
- Node: query_parser.Node{Off: 7},
- },
- vdl.ValueOf("v.io/syncbase/v23/syncbase/nosql/internal/query/test.Customer"),
- },
- {
- custTable.rows[0].key,
- custTable.rows[0].value,
- query_parser.Field{
- Segments: []query_parser.Segment{
- query_parser.Segment{
Value: "k",
Node: query_parser.Node{Off: 7},
},
@@ -2276,7 +2697,7 @@
}
for _, test := range basic {
- r, _, _ := query.ResolveField(db, test.k, test.v, &test.f)
+ r := query.ResolveField(db, test.k, test.v, &test.f)
if !reflect.DeepEqual(r, test.r) {
t.Errorf("got %v(%s), want %v(%s)", r, r.Type(), test.r, test.r.Type())
}
diff --git a/v23/syncbase/nosql/syncql/syncql.vdl b/v23/syncbase/nosql/syncql/syncql.vdl
index 75b58e2..f6267bf 100644
--- a/v23/syncbase/nosql/syncql/syncql.vdl
+++ b/v23/syncbase/nosql/syncql/syncql.vdl
@@ -7,7 +7,7 @@
// SyncQL errors
error (
BadFieldInWhere(off int64) {
- "en": "[{off}]Where field must be 'k', 'v[{.<ident>}...]' or 't'.",
+ "en": "[{off}]Where field must be 'k' or 'v[{.<ident>}...]'.",
}
BoolInvalidExpression(off int64) {
"en": "[{off}]Boolean operands may only be used in equals and not equals expressions.",
@@ -21,9 +21,6 @@
DotNotationDisallowedForKey(off int64) {
"en": "[{off}]Dot notation may not be used on a key field.",
}
- DotNotationDisallowedForType(off int64) {
- "en": "[{off}]Dot notation may not be used with type.",
- }
ErrorCompilingRegularExpression(off int64, regex string, err error) {
"en": "[{off}]The following error encountered compiling regex '{regex}': {err}",
}
@@ -54,8 +51,20 @@
FunctionNotFound(off int64, name string) {
"en": "[{off}]Function '{name}' not found.",
}
- FunctionReturnedError(off int64, name string, err error) {
- "en": "[{off}]Function '{name}' returned error: {err}.",
+ ArgMustBeField(off int64) {
+ "en": "[{off}]Argument must be a value field (i.e., must begin with 'v').",
+ }
+ TimeConversionError(off int64, err error) {
+ "en": "[{off}]Can't convert to time: {err}.",
+ }
+ LocationConversionError(off int64, err error) {
+ "en": "[{off}]Can't convert to location: {err}.",
+ }
+ StringConversionError(off int64, err error) {
+ "en": "[{off}]Can't convert to string: {err}.",
+ }
+ FloatConversionError(off int64, err error) {
+ "en": "[{off}]Can't convert to float: {err}.",
}
IsIsNotRequireLhsValue(off int64) {
"en": "[{off}]'Is/is not' expressions require left operand to be a value operand.",
@@ -70,8 +79,8 @@
InvalidSelectField(off int64) {
"en": "[{off}]Select field must be 'k' or 'v[{.<ident>}...]'.",
}
- KeyExpressionForm(off int64) {
- "en": "[{off}]Key (i.e., 'k') expressions must be of form 'k [=|<>|>|>=|<|<=|like|not like] <string-literal>'.",
+ KeyExpressionLiteral(off int64) {
+ "en": "[{off}]Key (i.e., 'k') compares against literals must be string literal.",
}
KeyValueStreamError(off int64, err error) {
"en": "[{off}]KeyValueStream error: {err}.",
@@ -94,9 +103,6 @@
TableCantAccess(off int64, table string, err error) {
"en": "[{off}]Table {table} does not exist (or cannot be accessed): {err}.",
}
- TypeExpressionForm(off int64) {
- "en": "[{off}]Type expressions must be 't = <string-literal>'.",
- }
Unexpected(off int64, found string) {
"en": "[{off}]Unexpected: {found}.",
}
diff --git a/v23/syncbase/nosql/syncql/syncql.vdl.go b/v23/syncbase/nosql/syncql/syncql.vdl.go
index 81531e6..778646d 100644
--- a/v23/syncbase/nosql/syncql/syncql.vdl.go
+++ b/v23/syncbase/nosql/syncql/syncql.vdl.go
@@ -15,12 +15,11 @@
)
var (
- ErrBadFieldInWhere = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.BadFieldInWhere", verror.NoRetry, "{1:}{2:} [{3}]Where field must be 'k', 'v[{.<ident>}...]' or 't'.")
+ ErrBadFieldInWhere = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.BadFieldInWhere", verror.NoRetry, "{1:}{2:} [{3}]Where field must be 'k' or 'v[{.<ident>}...]'.")
ErrBoolInvalidExpression = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.BoolInvalidExpression", verror.NoRetry, "{1:}{2:} [{3}]Boolean operands may only be used in equals and not equals expressions.")
ErrCheckOfUnknownStatementType = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.CheckOfUnknownStatementType", verror.NoRetry, "{1:}{2:} [{3}]Cannot semantically check unknown statement type.")
ErrCouldNotConvert = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.CouldNotConvert", verror.NoRetry, "{1:}{2:} [{3}]Could not convert {4} to {5}.")
ErrDotNotationDisallowedForKey = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.DotNotationDisallowedForKey", verror.NoRetry, "{1:}{2:} [{3}]Dot notation may not be used on a key field.")
- ErrDotNotationDisallowedForType = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.DotNotationDisallowedForType", verror.NoRetry, "{1:}{2:} [{3}]Dot notation may not be used with type.")
ErrErrorCompilingRegularExpression = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.ErrorCompilingRegularExpression", verror.NoRetry, "{1:}{2:} [{3}]The following error encountered compiling regex '{4}': {5}")
ErrExecOfUnknownStatementType = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.ExecOfUnknownStatementType", verror.NoRetry, "{1:}{2:} [{3}]Cannot execute unknown statement type: {4}.")
ErrExpected = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.Expected", verror.NoRetry, "{1:}{2:} [{3}]Expected '{4}'.")
@@ -31,12 +30,16 @@
ErrFunctionArgCount = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.FunctionArgCount", verror.NoRetry, "{1:}{2:} [{3}]Function '{4}' expects {5} args, found: {6}.")
ErrFunctionArgBad = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.FunctionArgBad", verror.NoRetry, "{1:}{2:} [{3}]Function '{4}' arg '{5}' could not be resolved.")
ErrFunctionNotFound = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.FunctionNotFound", verror.NoRetry, "{1:}{2:} [{3}]Function '{4}' not found.")
- ErrFunctionReturnedError = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.FunctionReturnedError", verror.NoRetry, "{1:}{2:} [{3}]Function '{4}' returned error: {5}.")
+ ErrArgMustBeField = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.ArgMustBeField", verror.NoRetry, "{1:}{2:} [{3}]Argument must be a value field (i.e., must begin with 'v').")
+ ErrTimeConversionError = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.TimeConversionError", verror.NoRetry, "{1:}{2:} [{3}]Can't convert to time: {4}.")
+ ErrLocationConversionError = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.LocationConversionError", verror.NoRetry, "{1:}{2:} [{3}]Can't convert to location: {4}.")
+ ErrStringConversionError = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.StringConversionError", verror.NoRetry, "{1:}{2:} [{3}]Can't convert to string: {4}.")
+ ErrFloatConversionError = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.FloatConversionError", verror.NoRetry, "{1:}{2:} [{3}]Can't convert to float: {4}.")
ErrIsIsNotRequireLhsValue = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.IsIsNotRequireLhsValue", verror.NoRetry, "{1:}{2:} [{3}]'Is/is not' expressions require left operand to be a value operand.")
ErrIsIsNotRequireRhsNil = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.IsIsNotRequireRhsNil", verror.NoRetry, "{1:}{2:} [{3}]'Is/is not' expressions require right operand to be nil.")
ErrInvalidEscapedChar = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.InvalidEscapedChar", verror.NoRetry, "{1:}{2:} [{3}Expected backslash, percent, or underscore after backslash.]")
ErrInvalidSelectField = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.InvalidSelectField", verror.NoRetry, "{1:}{2:} [{3}]Select field must be 'k' or 'v[{.<ident>}...]'.")
- ErrKeyExpressionForm = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.KeyExpressionForm", verror.NoRetry, "{1:}{2:} [{3}]Key (i.e., 'k') expressions must be of form 'k [=|<>|>|>=|<|<=|like|not like] <string-literal>'.")
+ ErrKeyExpressionLiteral = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.KeyExpressionLiteral", verror.NoRetry, "{1:}{2:} [{3}]Key (i.e., 'k') compares against literals must be string literal.")
ErrKeyValueStreamError = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.KeyValueStreamError", verror.NoRetry, "{1:}{2:} [{3}]KeyValueStream error: {4}.")
ErrLikeExpressionsRequireRhsString = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.LikeExpressionsRequireRhsString", verror.NoRetry, "{1:}{2:} [{3}]Like expressions require right operand of type <string-literal>.")
ErrLimitMustBeGe0 = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.LimitMustBeGe0", verror.NoRetry, "{1:}{2:} [{3}]Limit must be > 0.")
@@ -44,19 +47,17 @@
ErrOffsetMustBeGe0 = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.OffsetMustBeGe0", verror.NoRetry, "{1:}{2:} [{3}]Offset must be > 0.")
ErrScanError = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.ScanError", verror.NoRetry, "{1:}{2:} [{3}]Scan error: {4}.")
ErrTableCantAccess = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.TableCantAccess", verror.NoRetry, "{1:}{2:} [{3}]Table {4} does not exist (or cannot be accessed): {5}.")
- ErrTypeExpressionForm = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.TypeExpressionForm", verror.NoRetry, "{1:}{2:} [{3}]Type expressions must be 't = <string-literal>'.")
ErrUnexpected = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.Unexpected", verror.NoRetry, "{1:}{2:} [{3}]Unexpected: {4}.")
ErrUnexpectedEndOfStatement = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.UnexpectedEndOfStatement", verror.NoRetry, "{1:}{2:} [{3}]No statement found.")
ErrUnknownIdentifier = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.UnknownIdentifier", verror.NoRetry, "{1:}{2:} [{3}]Uknown identifier: {4}.")
)
func init() {
- i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrBadFieldInWhere.ID), "{1:}{2:} [{3}]Where field must be 'k', 'v[{.<ident>}...]' or 't'.")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrBadFieldInWhere.ID), "{1:}{2:} [{3}]Where field must be 'k' or 'v[{.<ident>}...]'.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrBoolInvalidExpression.ID), "{1:}{2:} [{3}]Boolean operands may only be used in equals and not equals expressions.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrCheckOfUnknownStatementType.ID), "{1:}{2:} [{3}]Cannot semantically check unknown statement type.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrCouldNotConvert.ID), "{1:}{2:} [{3}]Could not convert {4} to {5}.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrDotNotationDisallowedForKey.ID), "{1:}{2:} [{3}]Dot notation may not be used on a key field.")
- i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrDotNotationDisallowedForType.ID), "{1:}{2:} [{3}]Dot notation may not be used with type.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrErrorCompilingRegularExpression.ID), "{1:}{2:} [{3}]The following error encountered compiling regex '{4}': {5}")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrExecOfUnknownStatementType.ID), "{1:}{2:} [{3}]Cannot execute unknown statement type: {4}.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrExpected.ID), "{1:}{2:} [{3}]Expected '{4}'.")
@@ -67,12 +68,16 @@
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrFunctionArgCount.ID), "{1:}{2:} [{3}]Function '{4}' expects {5} args, found: {6}.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrFunctionArgBad.ID), "{1:}{2:} [{3}]Function '{4}' arg '{5}' could not be resolved.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrFunctionNotFound.ID), "{1:}{2:} [{3}]Function '{4}' not found.")
- i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrFunctionReturnedError.ID), "{1:}{2:} [{3}]Function '{4}' returned error: {5}.")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrArgMustBeField.ID), "{1:}{2:} [{3}]Argument must be a value field (i.e., must begin with 'v').")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrTimeConversionError.ID), "{1:}{2:} [{3}]Can't convert to time: {4}.")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrLocationConversionError.ID), "{1:}{2:} [{3}]Can't convert to location: {4}.")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrStringConversionError.ID), "{1:}{2:} [{3}]Can't convert to string: {4}.")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrFloatConversionError.ID), "{1:}{2:} [{3}]Can't convert to float: {4}.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrIsIsNotRequireLhsValue.ID), "{1:}{2:} [{3}]'Is/is not' expressions require left operand to be a value operand.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrIsIsNotRequireRhsNil.ID), "{1:}{2:} [{3}]'Is/is not' expressions require right operand to be nil.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrInvalidEscapedChar.ID), "{1:}{2:} [{3}Expected backslash, percent, or underscore after backslash.]")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrInvalidSelectField.ID), "{1:}{2:} [{3}]Select field must be 'k' or 'v[{.<ident>}...]'.")
- i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrKeyExpressionForm.ID), "{1:}{2:} [{3}]Key (i.e., 'k') expressions must be of form 'k [=|<>|>|>=|<|<=|like|not like] <string-literal>'.")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrKeyExpressionLiteral.ID), "{1:}{2:} [{3}]Key (i.e., 'k') compares against literals must be string literal.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrKeyValueStreamError.ID), "{1:}{2:} [{3}]KeyValueStream error: {4}.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrLikeExpressionsRequireRhsString.ID), "{1:}{2:} [{3}]Like expressions require right operand of type <string-literal>.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrLimitMustBeGe0.ID), "{1:}{2:} [{3}]Limit must be > 0.")
@@ -80,7 +85,6 @@
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrOffsetMustBeGe0.ID), "{1:}{2:} [{3}]Offset must be > 0.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrScanError.ID), "{1:}{2:} [{3}]Scan error: {4}.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrTableCantAccess.ID), "{1:}{2:} [{3}]Table {4} does not exist (or cannot be accessed): {5}.")
- i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrTypeExpressionForm.ID), "{1:}{2:} [{3}]Type expressions must be 't = <string-literal>'.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrUnexpected.ID), "{1:}{2:} [{3}]Unexpected: {4}.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrUnexpectedEndOfStatement.ID), "{1:}{2:} [{3}]No statement found.")
i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrUnknownIdentifier.ID), "{1:}{2:} [{3}]Uknown identifier: {4}.")
@@ -111,11 +115,6 @@
return verror.New(ErrDotNotationDisallowedForKey, ctx, off)
}
-// NewErrDotNotationDisallowedForType returns an error with the ErrDotNotationDisallowedForType ID.
-func NewErrDotNotationDisallowedForType(ctx *context.T, off int64) error {
- return verror.New(ErrDotNotationDisallowedForType, ctx, off)
-}
-
// NewErrErrorCompilingRegularExpression returns an error with the ErrErrorCompilingRegularExpression ID.
func NewErrErrorCompilingRegularExpression(ctx *context.T, off int64, regex string, err error) error {
return verror.New(ErrErrorCompilingRegularExpression, ctx, off, regex, err)
@@ -166,9 +165,29 @@
return verror.New(ErrFunctionNotFound, ctx, off, name)
}
-// NewErrFunctionReturnedError returns an error with the ErrFunctionReturnedError ID.
-func NewErrFunctionReturnedError(ctx *context.T, off int64, name string, err error) error {
- return verror.New(ErrFunctionReturnedError, ctx, off, name, err)
+// NewErrArgMustBeField returns an error with the ErrArgMustBeField ID.
+func NewErrArgMustBeField(ctx *context.T, off int64) error {
+ return verror.New(ErrArgMustBeField, ctx, off)
+}
+
+// NewErrTimeConversionError returns an error with the ErrTimeConversionError ID.
+func NewErrTimeConversionError(ctx *context.T, off int64, err error) error {
+ return verror.New(ErrTimeConversionError, ctx, off, err)
+}
+
+// NewErrLocationConversionError returns an error with the ErrLocationConversionError ID.
+func NewErrLocationConversionError(ctx *context.T, off int64, err error) error {
+ return verror.New(ErrLocationConversionError, ctx, off, err)
+}
+
+// NewErrStringConversionError returns an error with the ErrStringConversionError ID.
+func NewErrStringConversionError(ctx *context.T, off int64, err error) error {
+ return verror.New(ErrStringConversionError, ctx, off, err)
+}
+
+// NewErrFloatConversionError returns an error with the ErrFloatConversionError ID.
+func NewErrFloatConversionError(ctx *context.T, off int64, err error) error {
+ return verror.New(ErrFloatConversionError, ctx, off, err)
}
// NewErrIsIsNotRequireLhsValue returns an error with the ErrIsIsNotRequireLhsValue ID.
@@ -191,9 +210,9 @@
return verror.New(ErrInvalidSelectField, ctx, off)
}
-// NewErrKeyExpressionForm returns an error with the ErrKeyExpressionForm ID.
-func NewErrKeyExpressionForm(ctx *context.T, off int64) error {
- return verror.New(ErrKeyExpressionForm, ctx, off)
+// NewErrKeyExpressionLiteral returns an error with the ErrKeyExpressionLiteral ID.
+func NewErrKeyExpressionLiteral(ctx *context.T, off int64) error {
+ return verror.New(ErrKeyExpressionLiteral, ctx, off)
}
// NewErrKeyValueStreamError returns an error with the ErrKeyValueStreamError ID.
@@ -231,11 +250,6 @@
return verror.New(ErrTableCantAccess, ctx, off, table, err)
}
-// NewErrTypeExpressionForm returns an error with the ErrTypeExpressionForm ID.
-func NewErrTypeExpressionForm(ctx *context.T, off int64) error {
- return verror.New(ErrTypeExpressionForm, ctx, off)
-}
-
// NewErrUnexpected returns an error with the ErrUnexpected ID.
func NewErrUnexpected(ctx *context.T, off int64, found string) error {
return verror.New(ErrUnexpected, ctx, off, found)
diff --git a/x/ref/syncbase/sb51/doc.go b/x/ref/syncbase/sb51/doc.go
index 73609c1..0cd9c36 100644
--- a/x/ref/syncbase/sb51/doc.go
+++ b/x/ref/syncbase/sb51/doc.go
@@ -25,11 +25,11 @@
// Sample run (assuming a syncbase service is mounted at '/:8101/syncbase',
// otherwise specify using -service flag):
// > $V23_ROOT/roadmap/go/bin/sb51 sh -create-missing -make-demo -format=csv demoapp demodb
-// ? select v.Name, v.Address.State from DemoCustomers where t = "Customer";
+// ? select v.Name, v.Address.State from DemoCustomers where Type(v) = "Customer";
// v.Name,v.Address.State
// John Smith,CA
// Bat Masterson,IA
-// ? select v.CustId, v.InvoiceNum, v.ShipTo.Zip, v.Amount from DemoCustomers where t = "Invoice" and v.Amount > 100;
+// ? select v.CustId, v.InvoiceNum, v.ShipTo.Zip, v.Amount from DemoCustomers where Type(v) = "Invoice" and v.Amount > 100;
// v.CustId,v.InvoiceNum,v.ShipTo.Zip,v.Amount
// 2,1001,50055,166
// 2,1002,50055,243