syncbase: syncql: make k, v and functions case sensitive

Field specifications are case sensitive except for the k and v.
Change to also require the correct case for k and v.

For example,

        select V.Foo.Bar from Customer
	        ^
         Did you mean 'v'?

In addition, functions are now case sensitve and also provide a helpful error:

         select now() from Customer
                ^
         Did you mean 'Now'?

With this change, only syncQL reserved words are case insensitive.

Change-Id: I51b1f9958cf03a02473390b68c41d9bfced46b44
diff --git a/v23/syncbase/nosql/exec_test/exec_test.go b/v23/syncbase/nosql/exec_test/exec_test.go
index e8b10dc..1ddc151 100644
--- a/v23/syncbase/nosql/exec_test/exec_test.go
+++ b/v23/syncbase/nosql/exec_test/exec_test.go
@@ -762,8 +762,8 @@
 		},
 		// Test string functions in where clause.
 		{
-			// Select invoices shipped to Any street -- using LowerCase.
-			"select k from Customer where Type(v) like \"%.Invoice\" and LowerCase(v.ShipTo.Street) like \"%any%\"",
+			// Select invoices shipped to Any street -- using Lowercase.
+			"select k from Customer where Type(v) like \"%.Invoice\" and Lowercase(v.ShipTo.Street) like \"%any%\"",
 			[]string{"k"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf(customerEntries[5].key)},
@@ -773,8 +773,8 @@
 			},
 		},
 		{
-			// Select invoices shipped to Any street -- using UpperCase.
-			"select k from Customer where Type(v) like \"%.Invoice\" and UpperCase(v.ShipTo.Street) like \"%ANY%\"",
+			// Select invoices shipped to Any street -- using Uppercase.
+			"select k from Customer where Type(v) like \"%.Invoice\" and Uppercase(v.ShipTo.Street) like \"%ANY%\"",
 			[]string{"k"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf(customerEntries[5].key)},
@@ -818,9 +818,9 @@
 				[]*vdl.Value{vdl.ValueOf(t2015_07_01_01_23_45)},
 			},
 		},
-		// LowerCase function
+		// Lowercase function
 		{
-			"select LowerCase(v.Name) as name from Customer where Type(v) like \"%.Customer\"",
+			"select Lowercase(v.Name) as name from Customer where Type(v) like \"%.Customer\"",
 			[]string{"name"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf("john smith")},
@@ -828,9 +828,9 @@
 				[]*vdl.Value{vdl.ValueOf("john steed")},
 			},
 		},
-		// UpperCase function
+		// Uppercase function
 		{
-			"select UpperCase(v.Name) as NAME from Customer where Type(v) like \"%.Customer\"",
+			"select Uppercase(v.Name) as NAME from Customer where Type(v) like \"%.Customer\"",
 			[]string{"NAME"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf("JOHN SMITH")},
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 d28c9e2..f750dea 100644
--- a/v23/syncbase/nosql/internal/query/query_checker/query_checker.go
+++ b/v23/syncbase/nosql/internal/query/query_checker/query_checker.go
@@ -57,13 +57,19 @@
 	for _, selector := range s.Selectors {
 		switch selector.Type {
 		case query_parser.TypSelField:
-			switch strings.ToLower(selector.Field.Segments[0].Value) {
+			switch selector.Field.Segments[0].Value {
 			case "k":
 				if len(selector.Field.Segments) > 1 {
 					return syncql.NewErrDotNotationDisallowedForKey(db.GetContext(), selector.Field.Segments[1].Off)
 				}
 			case "v":
 				// Nothing to check.
+			case "K":
+				// Be nice and warn of mistakenly capped 'K'.
+				return syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), selector.Field.Segments[0].Off)
+			case "V":
+				// Be nice and warn of mistakenly capped 'V'.
+				return syncql.NewErrDidYouMeanLowercaseV(db.GetContext(), selector.Field.Segments[0].Off)
 			default:
 				return syncql.NewErrInvalidSelectField(db.GetContext(), selector.Field.Segments[0].Off)
 			}
@@ -169,12 +175,19 @@
 	case query_parser.TypExpr:
 		return checkExpression(db, o.Expr)
 	case query_parser.TypField:
-		switch strings.ToLower(o.Column.Segments[0].Value) {
+		switch 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":
+			// Nothing to do.
+		case "K":
+			// Be nice and warn of mistakenly capped 'K'.
+			return syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), o.Column.Segments[0].Off)
+		case "V":
+			// Be nice and warn of mistakenly capped 'V'.
+			return syncql.NewErrDidYouMeanLowercaseV(db.GetContext(), o.Column.Segments[0].Off)
 		default:
 			return syncql.NewErrBadFieldInWhere(db.GetContext(), o.Column.Segments[0].Off)
 		}
@@ -372,11 +385,11 @@
 }
 
 func IsKeyField(f *query_parser.Field) bool {
-	return strings.ToLower(f.Segments[0].Value) == "k"
+	return f.Segments[0].Value == "k"
 }
 
 func IsValueField(f *query_parser.Field) bool {
-	return strings.ToLower(f.Segments[0].Value) == "v"
+	return f.Segments[0].Value == "v"
 }
 
 func IsExpr(o *query_parser.Operand) bool {
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 95f1469..5188c52 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
@@ -432,17 +432,22 @@
 		{"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 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 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 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 Type(v) = \"Invoice\"", syncql.NewErrLocationConversionError(db.GetContext(), 24, errors.New("unknown time zone Foo"))},
+		{"select K from Customer where Type(v) = \"Invoice\"", syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 7)},
+		{"select V from Customer where Type(v) = \"Invoice\"", syncql.NewErrDidYouMeanLowercaseV(db.GetContext(), 7)},
+		{"select k from Customer where K = \"001\"", syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 29)},
+		{"select v from Customer where Type(V) = \"Invoice\"", syncql.NewErrDidYouMeanLowercaseV(db.GetContext(), 34)},
+		{"select K, V from Customer where Type(V) = \"Invoice\" and K = \"001\"", syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 7)},
 	}
 
 	for _, test := range basic {
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 250c089..cb7e40e 100644
--- a/v23/syncbase/nosql/internal/query/query_functions/query_functions.go
+++ b/v23/syncbase/nosql/internal/query/query_functions/query_functions.go
@@ -25,28 +25,35 @@
 }
 
 var functions map[string]function
+var lowercaseFunctions map[string]string // map of lowercase(funcName)->funcName
 
 func init() {
 	functions = make(map[string]function)
 
-	functions["date"] = function{[]query_parser.OperandType{query_parser.TypStr}, query_parser.TypTime, date, singleTimeArgCheck}
-	functions["datetime"] = function{[]query_parser.OperandType{query_parser.TypStr}, query_parser.TypTime, dateTime, singleTimeArgCheck}
-	functions["y"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, y, timeAndStringArgsCheck}
-	functions["ym"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ym, timeAndStringArgsCheck}
-	functions["ymd"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymd, timeAndStringArgsCheck}
-	functions["ymdh"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymdh, timeAndStringArgsCheck}
-	functions["ymdhm"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymdhm, timeAndStringArgsCheck}
-	functions["ymdhms"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymdhms, timeAndStringArgsCheck}
-	functions["now"] = function{[]query_parser.OperandType{}, query_parser.TypTime, now, nil}
+	functions["Date"] = function{[]query_parser.OperandType{query_parser.TypStr}, query_parser.TypTime, date, singleTimeArgCheck}
+	functions["DateTime"] = function{[]query_parser.OperandType{query_parser.TypStr}, query_parser.TypTime, dateTime, singleTimeArgCheck}
+	functions["Y"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, y, timeAndStringArgsCheck}
+	functions["YM"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ym, timeAndStringArgsCheck}
+	functions["YMD"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymd, timeAndStringArgsCheck}
+	functions["YMDH"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymdh, timeAndStringArgsCheck}
+	functions["YMDHM"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymdhm, timeAndStringArgsCheck}
+	functions["YMDHMS"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypTime, ymdhms, timeAndStringArgsCheck}
+	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["split"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypObject, split, twoStringArgsCheck}
-	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["Lowercase"] = function{[]query_parser.OperandType{query_parser.TypStr}, query_parser.TypStr, lowerCase, singleStringArgCheck}
+	functions["Split"] = function{[]query_parser.OperandType{query_parser.TypStr, query_parser.TypStr}, query_parser.TypObject, split, twoStringArgsCheck}
+	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}
+	functions["Complex"] = function{[]query_parser.OperandType{query_parser.TypFloat, query_parser.TypFloat}, query_parser.TypComplex, complexFunc, twoFloatsArgsCheck}
 
-	functions["len"] = function{[]query_parser.OperandType{query_parser.TypObject}, query_parser.TypInt, lenFunc, nil}
+	functions["Len"] = function{[]query_parser.OperandType{query_parser.TypObject}, query_parser.TypInt, lenFunc, nil}
+
+	// Build lowercaseFuncName->funcName
+	lowercaseFunctions = make(map[string]string)
+	for f := range functions {
+		lowercaseFunctions[strings.ToLower(f)] = f
+	}
 }
 
 // Check that function exists and that the number of args passed matches the spec.
@@ -57,8 +64,8 @@
 // early).  CheckFunction will fill in arg types, return types and may fill in
 // Computed and RetValue.
 func CheckFunction(db query_db.Database, f *query_parser.Function) error {
-	if entry, ok := functions[strings.ToLower(f.Name)]; !ok {
-		return syncql.NewErrFunctionNotFound(db.GetContext(), f.Off, f.Name)
+	if entry, err := lookupFuncName(db, f); err != nil {
+		return err
 	} else {
 		f.ArgTypes = entry.argTypes
 		f.RetType = entry.returnType
@@ -101,9 +108,23 @@
 	}
 }
 
+func lookupFuncName(db query_db.Database, f *query_parser.Function) (*function, error) {
+	if entry, ok := functions[f.Name]; !ok {
+		// No such function, is the case wrong?
+		if correctCase, ok := lowercaseFunctions[strings.ToLower(f.Name)]; !ok {
+			return nil, syncql.NewErrFunctionNotFound(db.GetContext(), f.Off, f.Name)
+		} else {
+			// the case is wrong
+			return nil, syncql.NewErrDidYouMeanFunction(db.GetContext(), f.Off, correctCase)
+		}
+	} else {
+		return &entry, nil
+	}
+}
+
 func FuncCheck(db query_db.Database, f *query_parser.Function, args []*query_parser.Operand) error {
-	if entry, ok := functions[strings.ToLower(f.Name)]; !ok {
-		return syncql.NewErrFunctionNotFound(db.GetContext(), f.Off, f.Name)
+	if entry, err := lookupFuncName(db, f); err != nil {
+		return err
 	} else {
 		if entry.checkArgsAddr != nil {
 			if err := entry.checkArgsAddr(db, f.Off, args); err != nil {
@@ -115,8 +136,8 @@
 }
 
 func ExecFunction(db query_db.Database, f *query_parser.Function, args []*query_parser.Operand) (*query_parser.Operand, error) {
-	if entry, ok := functions[strings.ToLower(f.Name)]; !ok {
-		return nil, syncql.NewErrFunctionNotFound(db.GetContext(), f.Off, f.Name)
+	if entry, err := lookupFuncName(db, f); err != nil {
+		return nil, err
 	} else {
 		retValue, err := entry.funcAddr(db, f.Off, args)
 		if err != nil {
@@ -194,7 +215,7 @@
 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" {
+	if args[0].Type != query_parser.TypField || len(args[0].Column.Segments) < 1 || args[0].Column.Segments[0].Value != "v" {
 		return syncql.NewErrArgMustBeField(db.GetContext(), args[0].Off)
 	}
 	return nil
diff --git a/v23/syncbase/nosql/internal/query/query_functions/query_functions_test.go b/v23/syncbase/nosql/internal/query/query_functions/query_functions_test.go
index fc5eae7..549cb9a 100644
--- a/v23/syncbase/nosql/internal/query/query_functions/query_functions_test.go
+++ b/v23/syncbase/nosql/internal/query/query_functions/query_functions_test.go
@@ -13,9 +13,11 @@
 	"v.io/syncbase/v23/syncbase/nosql/internal/query/query_functions"
 	"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"
 	"v.io/v23"
 	"v.io/v23/context"
 	"v.io/v23/vdl"
+	"v.io/v23/verror"
 	_ "v.io/x/ref/runtime/factories/generic"
 	"v.io/x/ref/test"
 )
@@ -49,6 +51,12 @@
 	result *query_parser.Operand
 }
 
+type functionsErrorTest struct {
+	f      *query_parser.Function
+	args   []*query_parser.Operand
+	err    error
+}
+
 var t_2015 time.Time
 var t_2015_06 time.Time
 var t_2015_06_21 time.Time
@@ -346,10 +354,10 @@
 				Time: t_2015_06_21_01_23_45,
 			},
 		},
-		// LowerCase
+		// Lowercase
 		functionsTest{
 			&query_parser.Function{
-				Name: "LowerCase",
+				Name: "Lowercase",
 				Args: []*query_parser.Operand{
 					&query_parser.Operand{
 						Type: query_parser.TypStr,
@@ -374,10 +382,10 @@
 				Str:  "foobar",
 			},
 		},
-		// UpperCase
+		// Uppercase
 		functionsTest{
 			&query_parser.Function{
-				Name: "UpperCase",
+				Name: "Uppercase",
 				Args: []*query_parser.Operand{
 					&query_parser.Operand{
 						Type: query_parser.TypStr,
@@ -561,3 +569,41 @@
 		}
 	}
 }
+
+func TestErrorFunctions(t *testing.T) {
+	tests := []functionsErrorTest{
+		// date
+		functionsErrorTest{
+			&query_parser.Function{
+				Name: "date",
+				Args: []*query_parser.Operand{
+					&query_parser.Operand{
+						Type: query_parser.TypStr,
+						Str:  "2015-06-21 PDT",
+					},
+				},
+				ArgTypes: []query_parser.OperandType{
+					query_parser.TypStr,
+				},
+				RetType:  query_parser.TypTime,
+				Computed: false,
+				RetValue: nil,
+				Node:  query_parser.Node{Off: 42},
+			},
+			[]*query_parser.Operand{
+				&query_parser.Operand{
+					Type: query_parser.TypStr,
+					Str:  "2015-06-21 PDT",
+				},
+			},
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), int64(42), "Date"),
+		},
+	}
+
+	for _, test := range tests {
+		_, err := query_functions.ExecFunction(&db, test.f, test.args)
+                if verror.ErrorID(err) != verror.ErrorID(test.err) || err.Error() != test.err.Error() {
+			t.Errorf("function: %v; got %v, want %v", test.f, err, test.err)
+		}
+	}
+}
diff --git a/v23/syncbase/nosql/internal/query/query_parser/doc.go b/v23/syncbase/nosql/internal/query/query_parser/doc.go
index 488ef23..c16c6bf 100644
--- a/v23/syncbase/nosql/internal/query/query_parser/doc.go
+++ b/v23/syncbase/nosql/internal/query/query_parser/doc.go
@@ -23,8 +23,8 @@
 // <selector> ::= <column> [AS <string_literal>]
 //
 // <column> ::=
-//   K
-//   | V[<period><field>]
+//   k
+//   | v[<period><field>]
 //   | <function>
 //
 // <field> ::= <segment>[{<period><segment>}...]
@@ -53,11 +53,11 @@
 //
 // <binary_expression> ::=
 //   <operand> <binary_op> <operand>
-//   | V[<period><field>] IS [NOT] NIL
+//   | v[<period><field>] IS [NOT] NIL
 //
 // <operand> ::=
-//   K
-//   | V[<period><field>]
+//   k
+//   | v[<period><field>]
 //   | <literal>
 //   | <function>
 //
diff --git a/v23/syncbase/nosql/internal/query/test/query_test.go b/v23/syncbase/nosql/internal/query/test/query_test.go
index 3c5464d..61c320a 100644
--- a/v23/syncbase/nosql/internal/query/test/query_test.go
+++ b/v23/syncbase/nosql/internal/query/test/query_test.go
@@ -1159,8 +1159,8 @@
 		},
 		// Test string functions in where clause.
 		{
-			// Select invoices shipped to Any street -- using LowerCase.
-			"select k from Customer where Type(v) like \"%.Invoice\" and LowerCase(v.ShipTo.Street) like \"%any%\"",
+			// Select invoices shipped to Any street -- using Lowercase.
+			"select k from Customer where Type(v) like \"%.Invoice\" and Lowercase(v.ShipTo.Street) like \"%any%\"",
 			[]string{"k"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf(custTable.rows[5].key)},
@@ -1170,8 +1170,8 @@
 			},
 		},
 		{
-			// Select invoices shipped to Any street -- using UpperCase.
-			"select k from Customer where Type(v) like \"%.Invoice\" and UpperCase(v.ShipTo.Street) like \"%ANY%\"",
+			// Select invoices shipped to Any street -- using Uppercase.
+			"select k from Customer where Type(v) like \"%.Invoice\" and Uppercase(v.ShipTo.Street) like \"%ANY%\"",
 			[]string{"k"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf(custTable.rows[5].key)},
@@ -1215,9 +1215,9 @@
 				[]*vdl.Value{vdl.ValueOf(t2015_07_01_01_23_45)},
 			},
 		},
-		// LowerCase function
+		// Lowercase function
 		{
-			"select LowerCase(v.Name) as name from Customer where Type(v) like \"%.Customer\"",
+			"select Lowercase(v.Name) as name from Customer where Type(v) like \"%.Customer\"",
 			[]string{"name"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf("john smith")},
@@ -1225,9 +1225,9 @@
 				[]*vdl.Value{vdl.ValueOf("john steed")},
 			},
 		},
-		// UpperCase function
+		// Uppercase function
 		{
-			"select UpperCase(v.Name) as NAME from Customer where Type(v) like \"%.Customer\"",
+			"select Uppercase(v.Name) as NAME from Customer where Type(v) like \"%.Customer\"",
 			[]string{"NAME"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf("JOHN SMITH")},
@@ -1325,8 +1325,8 @@
 		},
 		// Map in selection using function as key.
 		{
-			"select v.Credit.Report.TransUnionReport.PreviousRatings[UpperCase(\"2015q2\")] from Customer where v.Name = \"Bat Masterson\"",
-			[]string{"v.Credit.Report.TransUnionReport.PreviousRatings[UpperCase]"},
+			"select v.Credit.Report.TransUnionReport.PreviousRatings[Uppercase(\"2015q2\")] from Customer where v.Name = \"Bat Masterson\"",
+			[]string{"v.Credit.Report.TransUnionReport.PreviousRatings[Uppercase]"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf(int16(40))},
 			},
@@ -1351,8 +1351,8 @@
 		},
 		// Function using a map lookup as arg
 		{
-			"select UpperCase(v.B[true]) from ManyMaps",
-			[]string{"UpperCase"},
+			"select Uppercase(v.B[true]) from ManyMaps",
+			[]string{"Uppercase"},
 			[][]*vdl.Value{
 				[]*vdl.Value{vdl.ValueOf("IT WAS THE BEST OF TIMES,")},
 			},
@@ -1823,7 +1823,7 @@
 			svPairs(100, 300),
 		},
 		{
-			"select k, v.Key from BigTable where V.Key = K",
+			"select k, v.Key from BigTable where v.Key = k",
 			[]string{"k", "v.Key"},
 			svPairs(100, 300),
 		},
@@ -1858,8 +1858,8 @@
 			[][]*vdl.Value{},
 		},
 		{
-			"select K, V.Key from BigTable where k >= v.Key",
-			[]string{"K", "V.Key"},
+			"select k, v.Key from BigTable where k >= v.Key",
+			[]string{"k", "v.Key"},
 			svPairs(100, 300),
 		},
 		{
@@ -1868,8 +1868,8 @@
 			svPairs(100, 300),
 		},
 		{
-			"select K, V.Key from BigTable where k <= v.Key",
-			[]string{"K", "V.Key"},
+			"select k, v.Key from BigTable where k <= v.Key",
+			[]string{"k", "v.Key"},
 			svPairs(100, 300),
 		},
 		{
@@ -2708,6 +2708,94 @@
 			"select v from Customer where Len(10) = 3",
 			syncql.NewErrFunctionLenInvalidArg(db.GetContext(), 33),
 		},
+		{
+			"select K from Customer where Type(v) = \"Invoice\"",
+			syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 7),
+		},
+		{
+			"select V from Customer where Type(v) = \"Invoice\"",
+			syncql.NewErrDidYouMeanLowercaseV(db.GetContext(), 7),
+		},
+		{
+			"select k from Customer where K = \"001\"",
+			syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 29),
+		},
+		{
+			"select v from Customer where Type(V) = \"Invoice\"",
+			syncql.NewErrDidYouMeanLowercaseV(db.GetContext(), 34),
+		},
+		{
+			"select K, V from Customer where Type(V) = \"Invoice\" and K = \"001\"",
+			syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 7),
+		},
+		{
+			"select type(v) from Customer where Type(v) = \"Invoice\"",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Type"),
+		},
+		{
+			"select Type(v) from Customer where type(v) = \"Invoice\"",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 35, "Type"),
+		},
+		{
+			"select type(v) from Customer where type(v) = \"Invoice\"",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Type"),
+		},
+		{
+			"select date(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Date"),
+		},
+		{
+			"select Datetime(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "DateTime"),
+		},
+		{
+			"select y(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Y"),
+		},
+		{
+			"select ym(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "YM"),
+		},
+		{
+			"select ymd(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "YMD"),
+		},
+		{
+			"select ymdh(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "YMDH"),
+		},
+		{
+			"select ymdhm(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "YMDHM"),
+		},
+		{
+			"select ymdhms(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "YMDHMS"),
+		},
+		{
+			"select now() from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Now"),
+		},
+		{
+			"select LowerCase(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Lowercase"),
+		},
+		{
+			"select UPPERCASE(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Uppercase"),
+		},
+		{
+			"select spliT(\"foo:bar\", \":\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Split"),
+		},
+		{
+			"select comPLex(1.0, 2.0) from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Complex"),
+		},
+		{
+			"select len(\"foo\") from Customer",
+			syncql.NewErrDidYouMeanFunction(db.GetContext(), 7, "Len"),
+		},
 	}
 
 	for _, test := range basic {
diff --git a/v23/syncbase/nosql/syncql/syncql.vdl b/v23/syncbase/nosql/syncql/syncql.vdl
index 810c3e0..4fda53f 100644
--- a/v23/syncbase/nosql/syncql/syncql.vdl
+++ b/v23/syncbase/nosql/syncql/syncql.vdl
@@ -118,4 +118,13 @@
 	UnknownIdentifier(off int64, found string) {
 		"en": "[{off}]Uknown identifier: {found}.",
 	}
+	DidYouMeanLowercaseK(off int64) {
+		"en": "[{off}]Did you mean: 'k'?",
+	}
+	DidYouMeanLowercaseV(off int64) {
+		"en": "[{off}]Did you mean: 'v'?",
+	}
+	DidYouMeanFunction(off int64, correctName string) {
+		"en": "[{off}]Did you mean: '{correctName}'?",
+	}
 )
diff --git a/v23/syncbase/nosql/syncql/syncql.vdl.go b/v23/syncbase/nosql/syncql/syncql.vdl.go
index 1d4e2b4..0b5babc 100644
--- a/v23/syncbase/nosql/syncql/syncql.vdl.go
+++ b/v23/syncbase/nosql/syncql/syncql.vdl.go
@@ -52,6 +52,9 @@
 	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}.")
+	ErrDidYouMeanLowercaseK            = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.DidYouMeanLowercaseK", verror.NoRetry, "{1:}{2:} [{3}]Did you mean: 'k'?")
+	ErrDidYouMeanLowercaseV            = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.DidYouMeanLowercaseV", verror.NoRetry, "{1:}{2:} [{3}]Did you mean: 'v'?")
+	ErrDidYouMeanFunction              = verror.Register("v.io/syncbase/v23/syncbase/nosql/syncql.DidYouMeanFunction", verror.NoRetry, "{1:}{2:} [{3}]Did you mean: '{4}'?")
 )
 
 func init() {
@@ -92,6 +95,9 @@
 	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}.")
+	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrDidYouMeanLowercaseK.ID), "{1:}{2:} [{3}]Did you mean: 'k'?")
+	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrDidYouMeanLowercaseV.ID), "{1:}{2:} [{3}]Did you mean: 'v'?")
+	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrDidYouMeanFunction.ID), "{1:}{2:} [{3}]Did you mean: '{4}'?")
 }
 
 // NewErrBadFieldInWhere returns an error with the ErrBadFieldInWhere ID.
@@ -278,3 +284,18 @@
 func NewErrUnknownIdentifier(ctx *context.T, off int64, found string) error {
 	return verror.New(ErrUnknownIdentifier, ctx, off, found)
 }
+
+// NewErrDidYouMeanLowercaseK returns an error with the ErrDidYouMeanLowercaseK ID.
+func NewErrDidYouMeanLowercaseK(ctx *context.T, off int64) error {
+	return verror.New(ErrDidYouMeanLowercaseK, ctx, off)
+}
+
+// NewErrDidYouMeanLowercaseV returns an error with the ErrDidYouMeanLowercaseV ID.
+func NewErrDidYouMeanLowercaseV(ctx *context.T, off int64) error {
+	return verror.New(ErrDidYouMeanLowercaseV, ctx, off)
+}
+
+// NewErrDidYouMeanFunction returns an error with the ErrDidYouMeanFunction ID.
+func NewErrDidYouMeanFunction(ctx *context.T, off int64, correctName string) error {
+	return verror.New(ErrDidYouMeanFunction, ctx, off, correctName)
+}