Beispiel #1
0
// AsInterface converts the ValExpr to an interface. It converts
// ValTuple to []interface{}, ValArg to string, StrVal to sqltypes.String,
// NumVal to sqltypes.Numeric, NullVal to nil.
// Otherwise, it returns an error.
func AsInterface(node ValExpr) (interface{}, error) {
	switch node := node.(type) {
	case ValTuple:
		vals := make([]interface{}, 0, len(node))
		for _, val := range node {
			v, err := AsInterface(val)
			if err != nil {
				return nil, err
			}
			vals = append(vals, v)
		}
		return vals, nil
	case ValArg:
		return string(node), nil
	case ListArg:
		return string(node), nil
	case StrVal:
		return sqltypes.MakeString(node), nil
	case NumVal:
		n, err := sqltypes.BuildNumeric(string(node))
		if err != nil {
			return nil, fmt.Errorf("type mismatch: %s", err)
		}
		return n, nil
	case *NullVal:
		return nil, nil
	}
	return nil, fmt.Errorf("unexpected node %v", node)
}
Beispiel #2
0
func (node StrVal) Format(buf *TrackedBuffer) {
	s := sqltypes.MakeString([]byte(node))
	s.EncodeSql(buf)
}
func TestParsedQuery(t *testing.T) {
	tcases := []struct {
		desc     string
		query    string
		bindVars map[string]interface{}
		output   string
	}{
		{
			"no subs",
			"select * from a where id = 2",
			map[string]interface{}{
				"id": 1,
			},
			"select * from a where id = 2",
		}, {
			"simple bindvar sub",
			"select * from a where id1 = :id1 and id2 = :id2",
			map[string]interface{}{
				"id1": 1,
				"id2": nil,
			},
			"select * from a where id1 = 1 and id2 = null",
		}, {
			"missing bind var",
			"select * from a where id1 = :id1 and id2 = :id2",
			map[string]interface{}{
				"id1": 1,
			},
			"missing bind var id2",
		}, {
			"unencodable bind var",
			"select * from a where id1 = :id",
			map[string]interface{}{
				"id": make([]int, 1),
			},
			"unsupported bind variable type []int: [0]",
		}, {
			"list inside bind vars",
			"select * from a where id in (:vals)",
			map[string]interface{}{
				"vals": []sqltypes.Value{
					sqltypes.MakeNumeric([]byte("1")),
					sqltypes.MakeString([]byte("aa")),
				},
			},
			"select * from a where id in (1, 'aa')",
		}, {
			"two lists inside bind vars",
			"select * from a where id in (:vals)",
			map[string]interface{}{
				"vals": [][]sqltypes.Value{
					[]sqltypes.Value{
						sqltypes.MakeNumeric([]byte("1")),
						sqltypes.MakeString([]byte("aa")),
					},
					[]sqltypes.Value{
						sqltypes.Value{},
						sqltypes.MakeString([]byte("bb")),
					},
				},
			},
			"select * from a where id in ((1, 'aa'), (null, 'bb'))",
		}, {
			"list bind vars",
			"select * from a where id in ::vals",
			map[string]interface{}{
				"vals": []interface{}{
					1,
					"aa",
				},
			},
			"select * from a where id in (1, 'aa')",
		}, {
			"list bind vars single argument",
			"select * from a where id in ::vals",
			map[string]interface{}{
				"vals": []interface{}{
					1,
				},
			},
			"select * from a where id in (1)",
		}, {
			"list bind vars 0 arguments",
			"select * from a where id in ::vals",
			map[string]interface{}{
				"vals": []interface{}{},
			},
			"empty list supplied for vals",
		}, {
			"non-list bind var supplied",
			"select * from a where id in ::vals",
			map[string]interface{}{
				"vals": 1,
			},
			"unexpected list arg type int for key vals",
		}, {
			"list bind var for non-list",
			"select * from a where id = :vals",
			map[string]interface{}{
				"vals": []interface{}{1},
			},
			"unexpected arg type []interface {} for key vals",
		}, {
			"single column tuple equality",
			// We have to use an incorrect construct to get around the parser.
			"select * from a where b = :equality",
			map[string]interface{}{
				"equality": TupleEqualityList{
					Columns: []string{"pk"},
					Rows: [][]sqltypes.Value{
						[]sqltypes.Value{sqltypes.MakeNumeric([]byte("1"))},
						[]sqltypes.Value{sqltypes.MakeString([]byte("aa"))},
					},
				},
			},
			"select * from a where b = pk in (1, 'aa')",
		}, {
			"multi column tuple equality",
			"select * from a where b = :equality",
			map[string]interface{}{
				"equality": TupleEqualityList{
					Columns: []string{"pk1", "pk2"},
					Rows: [][]sqltypes.Value{
						[]sqltypes.Value{
							sqltypes.MakeNumeric([]byte("1")),
							sqltypes.MakeString([]byte("aa")),
						},
						[]sqltypes.Value{
							sqltypes.MakeNumeric([]byte("2")),
							sqltypes.MakeString([]byte("bb")),
						},
					},
				},
			},
			"select * from a where b = (pk1 = 1 and pk2 = 'aa') or (pk1 = 2 and pk2 = 'bb')",
		}, {
			"0 rows",
			"select * from a where b = :equality",
			map[string]interface{}{
				"equality": TupleEqualityList{
					Columns: []string{"pk"},
					Rows:    [][]sqltypes.Value{},
				},
			},
			"cannot encode with 0 rows",
		}, {
			"values don't match column count",
			"select * from a where b = :equality",
			map[string]interface{}{
				"equality": TupleEqualityList{
					Columns: []string{"pk"},
					Rows: [][]sqltypes.Value{
						[]sqltypes.Value{
							sqltypes.MakeNumeric([]byte("1")),
							sqltypes.MakeString([]byte("aa")),
						},
					},
				},
			},
			"values don't match column count",
		},
	}

	for _, tcase := range tcases {
		tree, err := Parse(tcase.query)
		if err != nil {
			t.Errorf("parse failed for %s: %v", tcase.desc, err)
			continue
		}
		buf := NewTrackedBuffer(nil)
		buf.Myprintf("%v", tree)
		pq := buf.ParsedQuery()
		bytes, err := pq.GenerateQuery(tcase.bindVars)
		var got string
		if err != nil {
			got = err.Error()
		} else {
			got = string(bytes)
		}
		if got != tcase.output {
			t.Errorf("for test case: %s, got: '%s', want '%s'", tcase.desc, got, tcase.output)
		}
	}
}