예제 #1
0
// Send forwards the call for further processing.
func (s *Server) exec(call sqlwire.Call) {
	req := call.Args
	resp := call.Reply
	stmt, err := parser.Parse(req.Sql)
	if err != nil {
		resp.SetGoError(err)
		return
	}
	switch p := stmt.(type) {
	case *parser.CreateDatabase:
		s.CreateDatabase(p, req.Params, resp)
	case *parser.CreateTable:
		s.CreateTable(p, req.Params, resp)
	case *parser.Delete:
		s.Delete(p, req.Params, resp)
	case *parser.Insert:
		s.Insert(p, req.Params, resp)
	case *parser.Select:
		s.Select(p, req.Params, resp)
	case *parser.ShowColumns:
		s.ShowColumns(p, req.Params, resp)
	case *parser.ShowDatabases:
		s.ShowDatabases(p, req.Params, resp)
	case *parser.ShowIndex:
		s.ShowIndex(p, req.Params, resp)
	case *parser.ShowTables:
		s.ShowTables(p, req.Params, resp)
	case *parser.Update:
		s.Update(p, req.Params, resp)
	case *parser.Use:
		s.Use(p, req.Params, resp)
	default:
		resp.SetGoError(fmt.Errorf("unknown statement type: %T", stmt))
	}
}
예제 #2
0
파일: conn.go 프로젝트: Jaekyun/cockroach
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	stmt, err := parser.Parse(query)
	if err != nil {
		return nil, err
	}
	return c.exec(stmt, args)
}
예제 #3
0
파일: conn.go 프로젝트: Jaekyun/cockroach
func (c *conn) Prepare(query string) (driver.Stmt, error) {
	s, err := parser.Parse(query)
	if err != nil {
		return nil, err
	}
	return &stmt{conn: c, stmt: s}, nil
}
예제 #4
0
파일: conn.go 프로젝트: Jaekyun/cockroach
func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	stmt, err := parser.Parse(query)
	if err != nil {
		return nil, err
	}
	return c.query(stmt, args)
}
예제 #5
0
// exec executes the request. Any error encountered is returned; it is
// the caller's responsibility to update the response.
func (s *Server) exec(req driver.Request) (driver.Response, error) {
	var resp driver.Response

	// Pick up current session state.
	planner := planner{db: s.db}
	if req.Session != nil {
		// TODO(tschottdorf) will have to validate the Session information (for
		// instance, whether access to the stored database is permitted).
		if err := gogoproto.Unmarshal(req.Session, &planner.session); err != nil {
			return resp, err
		}
	}
	stmts, err := parser.Parse(req.Sql)
	if err != nil {
		return resp, err
	}
	for _, stmt := range stmts {
		// Bind all the placeholder variables in the stmt to actual values.
		if err := parser.FillArgs(stmt, parameters(req.Params)); err != nil {
			return resp, err
		}
		var plan planNode
		if plan, err = planner.makePlan(stmt); err != nil {
			return resp, err
		}

		result := driver.Result{
			Columns: plan.Columns(),
		}
		for plan.Next() {
			values := plan.Values()
			row := driver.Result_Row{}
			row.Values = make([]driver.Datum, 0, len(values))
			for _, val := range values {
				switch vt := val.(type) {
				case parser.DBool:
					row.Values = append(row.Values, driver.Datum{BoolVal: (*bool)(&vt)})
				case parser.DInt:
					row.Values = append(row.Values, driver.Datum{IntVal: (*int64)(&vt)})
				case parser.DFloat:
					row.Values = append(row.Values, driver.Datum{FloatVal: (*float64)(&vt)})
				case parser.DString:
					row.Values = append(row.Values, driver.Datum{StringVal: (*string)(&vt)})
				case parser.DNull:
					row.Values = append(row.Values, driver.Datum{})
				default:
					return resp, util.Errorf("unsupported datum: %T", val)
				}
			}
			result.Rows = append(result.Rows, row)
		}
		resp.Results = append(resp.Results, result)
	}

	// Update session state.
	resp.Session, err = gogoproto.Marshal(&planner.session)
	return resp, err
}
예제 #6
0
파일: main.go 프로젝트: cockroachdb/go-fuzz
func fuzzSingle(stmt parser.Statement) (interestingness int) {
	var lastExpr parser.Expr
	rcvr := func() {
		if r := recover(); r != nil {
			if !expected(fmt.Sprintf("%v", r)) {
				fmt.Printf("Stmt: %s\n%s", stmt, spew.Sdump(stmt))
				if lastExpr != nil {
					fmt.Printf("Expr: %s", spew.Sdump(lastExpr))
				}
				panic(r)
			}
			// Anything that has expected errors in it is fine, but not as
			// interesting as things that go through.
			interestingness = 1
		}
	}
	defer rcvr()

	data0 := stmt.String()
	// TODO(tschottdorf): again, this is since we're ignoring stuff in the
	// grammar instead of erroring out on unsupported language. See:
	// https://github.com/cockroachdb/cockroach/issues/1949
	if strings.Contains(data0, "%!s(<nil>)") {
		return 0
	}
	stmt1, err := parser.Parse(data0)
	if err != nil {
		fmt.Printf("AST: %s", spew.Sdump(stmt))
		fmt.Printf("data0: %q\n", data0)
		panic(err)
	}
	interestingness = 2

	data1 := stmt1.String()
	// TODO(tschottdorf): due to the ignoring issue again.
	// if !reflect.DeepEqual(stmt, stmt1) {
	if data1 != data0 {
		fmt.Printf("data0: %q\n", data0)
		fmt.Printf("AST: %s", spew.Sdump(stmt))
		fmt.Printf("data1: %q\n", data1)
		fmt.Printf("AST: %s", spew.Sdump(stmt1))
		panic("not equal")
	}

	var v visitorFunc = func(e parser.Expr) parser.Expr {
		lastExpr = e
		if _, err := parser.EvalExpr(e); err != nil {
			panic(err)
		}
		return e
	}
	parser.WalkStmt(v, stmt)
	return
}
예제 #7
0
// Send forwards the call for further processing.
func (s *Server) exec(call sqlwire.Call) {
	req := call.Args
	resp := call.Reply
	// Pick up current session state.
	var session Session
	if req.Session != nil {
		if err := gogoproto.Unmarshal(req.Session, &session); err != nil {
			resp.SetGoError(err)
			return
		}
	}
	stmt, err := parser.Parse(req.Sql)
	if err != nil {
		resp.SetGoError(err)
		return
	}
	switch p := stmt.(type) {
	case *parser.CreateDatabase:
		s.CreateDatabase(&session, p, req.Params, resp)
	case *parser.CreateTable:
		s.CreateTable(&session, p, req.Params, resp)
	case *parser.Delete:
		s.Delete(&session, p, req.Params, resp)
	case *parser.Insert:
		s.Insert(&session, p, req.Params, resp)
	case *parser.Select:
		s.Select(&session, p, req.Params, resp)
	case *parser.ShowColumns:
		s.ShowColumns(&session, p, req.Params, resp)
	case *parser.ShowDatabases:
		s.ShowDatabases(&session, p, req.Params, resp)
	case *parser.ShowIndex:
		s.ShowIndex(&session, p, req.Params, resp)
	case *parser.ShowTables:
		s.ShowTables(&session, p, req.Params, resp)
	case *parser.Update:
		s.Update(&session, p, req.Params, resp)
	case *parser.Use:
		s.Use(&session, p, req.Params, resp)
	default:
		resp.SetGoError(fmt.Errorf("unknown statement type: %T", stmt))
	}
	// Update session state.
	if resp.Error != nil {
		return
	}
	payload, err := gogoproto.Marshal(&session)
	if err != nil {
		resp.SetGoError(util.Errorf("unable to marshal %+v to protobuf: %s", session, err))
		return
	}
	resp.Session = payload
}
예제 #8
0
// Send forwards the call for further processing.
func (s *Server) exec(call sqlwire.Call) error {
	req := call.Args
	resp := call.Reply
	// Pick up current session state.
	var session Session
	if req.Session != nil {
		// TODO(tschottdorf) will have to validate the Session information (for
		// instance, whether access to the stored database is permitted).
		if err := gogoproto.Unmarshal(req.Session, &session); err != nil {
			return err
		}
	}
	stmts, err := parser.Parse(req.Sql)
	if err != nil {
		return err
	}
	for _, stmt := range stmts {
		switch p := stmt.(type) {
		case *parser.CreateDatabase:
			err = s.CreateDatabase(&session, p, req.Params, resp)
		case *parser.CreateTable:
			err = s.CreateTable(&session, p, req.Params, resp)
		case *parser.Delete:
			err = s.Delete(&session, p, req.Params, resp)
		case *parser.Insert:
			err = s.Insert(&session, p, req.Params, resp)
		case *parser.Select:
			err = s.Select(&session, p, req.Params, resp)
		case *parser.Set:
			err = s.Set(&session, p, req.Params, resp)
		case *parser.ShowColumns:
			err = s.ShowColumns(&session, p, req.Params, resp)
		case *parser.ShowDatabases:
			err = s.ShowDatabases(&session, p, req.Params, resp)
		case *parser.ShowIndex:
			err = s.ShowIndex(&session, p, req.Params, resp)
		case *parser.ShowTables:
			err = s.ShowTables(&session, p, req.Params, resp)
		case *parser.Update:
			err = s.Update(&session, p, req.Params, resp)
		default:
			err = fmt.Errorf("unknown statement type: %T", stmt)
		}
		if err != nil {
			return err
		}
	}

	// Update session state.
	resp.Session, err = gogoproto.Marshal(&session)
	return err
}
예제 #9
0
파일: main.go 프로젝트: sjn1978/go-fuzz
// Fuzz is the entry point for go-fuzz. Run it via
//	  go-fuzz-build github.com/cockroachdb/go-fuzz/examples/parser && \
//    go-fuzz -bin=./parser-fuzz.zip -workdir=.
func Fuzz(data []byte) (interestingness int) {
	sql := string(data)
	stmts, err := parser.Parse(sql)
	if err != nil || stmts == nil {
		if stmts != nil {
			panic("stmt is not nil on error")
		}
		return
	}
	for _, stmt := range stmts {
		interestingness = fuzzSingle(stmt)
	}
	return
}
예제 #10
0
func TestPrimaryKeyUnspecified(t *testing.T) {
	defer leaktest.AfterTest(t)
	stmt, err := parser.Parse("CREATE TABLE test (a INT, b INT, CONSTRAINT c UNIQUE (b))")
	if err != nil {
		t.Fatal(err)
	}
	desc, err := makeTableDesc(stmt[0].(*parser.CreateTable))
	if err != nil {
		t.Fatal(err)
	}
	if err := desc.AllocateIDs(); err != structured.ErrMissingPrimaryKey {
		t.Fatal(err)
	}
}
예제 #11
0
// Send forwards the call for further processing.
func (s *Server) exec(call sqlwire.Call) error {
	req := call.Args
	resp := call.Reply
	// Pick up current session state.
	var session Session
	if req.Session != nil {
		if err := gogoproto.Unmarshal(req.Session, &session); err != nil {
			return err
		}
	}
	stmt, err := parser.Parse(req.Sql)
	if err != nil {
		return err
	}
	switch p := stmt.(type) {
	case *parser.CreateDatabase:
		err = s.CreateDatabase(&session, p, req.Params, resp)
	case *parser.CreateTable:
		err = s.CreateTable(&session, p, req.Params, resp)
	case *parser.Delete:
		err = s.Delete(&session, p, req.Params, resp)
	case *parser.Insert:
		err = s.Insert(&session, p, req.Params, resp)
	case *parser.Select:
		err = s.Select(&session, p, req.Params, resp)
	case *parser.ShowColumns:
		err = s.ShowColumns(&session, p, req.Params, resp)
	case *parser.ShowDatabases:
		err = s.ShowDatabases(&session, p, req.Params, resp)
	case *parser.ShowIndex:
		err = s.ShowIndex(&session, p, req.Params, resp)
	case *parser.ShowTables:
		err = s.ShowTables(&session, p, req.Params, resp)
	case *parser.Update:
		err = s.Update(&session, p, req.Params, resp)
	case *parser.Use:
		s.Use(&session, p, req.Params, resp)
	default:
		err = fmt.Errorf("unknown statement type: %T", stmt)
	}
	if err != nil {
		return err
	}

	// Update session state.
	resp.Session, err = gogoproto.Marshal(&session)
	return err
}
예제 #12
0
파일: server.go 프로젝트: slavau/cockroach
// exec executes the request. Any error encountered is returned; it is
// the caller's responsibility to update the response.
func (s server) execStmts(sql string, params parameters, planMaker *planner) driver.Response {
	var resp driver.Response
	stmts, err := parser.Parse(sql, parser.Syntax(planMaker.session.Syntax))
	if err != nil {
		// A parse error occured: we can't determine if there were multiple
		// statements or only one, so just pretend there was one.
		resp.Results = append(resp.Results, rollbackTxnAndReturnResultWithError(planMaker, err))
		return resp
	}
	for _, stmt := range stmts {
		result, err := s.execStmt(stmt, params, planMaker)
		if err != nil {
			result = rollbackTxnAndReturnResultWithError(planMaker, err)
		}
		resp.Results = append(resp.Results, result)
	}
	return resp
}
예제 #13
0
func TestPrimaryKeyUnspecified(t *testing.T) {
	defer leaktest.AfterTest(t)
	stmt, err := parser.Parse("CREATE TABLE foo.test (a INT, b INT, CONSTRAINT c UNIQUE (b))")
	if err != nil {
		t.Fatal(err)
	}
	create := stmt[0].(*parser.CreateTable)
	if err := create.Table.NormalizeTableName(""); err != nil {
		t.Fatal(err)
	}
	desc, err := makeTableDesc(create)
	if err != nil {
		t.Fatal(err)
	}
	if err := desc.AllocateIDs(); err != ErrMissingPrimaryKey {
		t.Fatal(err)
	}
}
예제 #14
0
func TestMakeDatabaseDesc(t *testing.T) {
	defer leaktest.AfterTest(t)

	stmt, err := parser.Parse("CREATE DATABASE test")
	if err != nil {
		t.Fatal(err)
	}
	desc := makeDatabaseDesc(stmt[0].(*parser.CreateDatabase))
	if desc.Name != "test" {
		t.Fatalf("expected Name == test, got %s", desc.Name)
	}
	// ID is not set yet.
	if desc.ID != 0 {
		t.Fatalf("expected ID == 0, got %d", desc.ID)
	}
	if len(desc.GetPrivileges().Users) != 1 {
		t.Fatalf("wrong number of privilege users, expected 1, got: %d", len(desc.GetPrivileges().Users))
	}
}
예제 #15
0
func init() {
	const sql = `
CREATE TABLE system.namespace (
  "parentID" INT,
  "name"     CHAR,
  "id"       INT,
  PRIMARY KEY (parentID, name)
);

CREATE TABLE system.descriptor (
  "id"   INT PRIMARY KEY,
  "desc" BLOB
);
`
	stmts, err := parser.Parse(sql)
	if err != nil {
		log.Fatal(err)
	}

	NamespaceTable, err = makeTableDesc(stmts[0].(*parser.CreateTable))
	if err != nil {
		log.Fatal(err)
	}
	NamespaceTable.Privileges = SystemDB.Privileges
	NamespaceTable.ID = namespaceTableID
	if err := NamespaceTable.AllocateIDs(); err != nil {
		log.Fatal(err)
	}

	DescriptorTable, err = makeTableDesc(stmts[1].(*parser.CreateTable))
	if err != nil {
		log.Fatal(err)
	}
	DescriptorTable.Privileges = SystemDB.Privileges
	DescriptorTable.ID = descriptorTableID
	if err := DescriptorTable.AllocateIDs(); err != nil {
		log.Fatal(err)
	}
}
예제 #16
0
func TestMakeDatabaseDesc(t *testing.T) {
	defer leaktest.AfterTest(t)

	stmt, err := parser.Parse("CREATE DATABASE test")
	if err != nil {
		t.Fatal(err)
	}
	desc := makeDatabaseDesc(stmt[0].(*parser.CreateDatabase))
	if desc.Name != "test" {
		t.Fatalf("expected Name == test, got %s", desc.Name)
	}
	// ID is not set yet.
	if desc.ID != 0 {
		t.Fatalf("expected ID == 0, got %d", desc.ID)
	}
	if len(desc.Read) != 1 || desc.Read[0] != security.RootUser {
		t.Fatalf("expected read == [root], got: %v", desc.Read)
	}
	if len(desc.Write) != 1 || desc.Write[0] != security.RootUser {
		t.Fatalf("expected write == [root], got: %v", desc.Write)
	}
}
예제 #17
0
func TestEvalExprError(t *testing.T) {
	testData := []struct {
		expr     string
		expected string
	}{
		{`'a' + 0`, `parsing \"a\": invalid syntax`},
		{`'0a' + 0`, `parsing \"0a\": invalid syntax`},
		{`a`, `column \"a\" not found`},
		// TODO(pmattis): Check for overflow.
		// {`~0 + 1`, `0`, nil},
	}
	for i, d := range testData {
		q, err := parser.Parse("SELECT " + d.expr)
		if err != nil {
			t.Fatalf("%d: %v: %s", i, err, d.expr)
		}
		expr := q.(*parser.Select).Exprs[0].(*parser.NonStarExpr).Expr
		if _, err := EvalExpr(expr, mapEnv{}); !testutils.IsError(err, d.expected) {
			t.Errorf("%d: expected %s, but found %v", i, d.expected, err)
		}
	}
}
예제 #18
0
// Send forwards the call for further processing.
func (s *Server) send(call sqlwire.Call) {
	req := call.Args
	resp := call.Reply
	stmt, err := parser.Parse(req.Sql)
	if err != nil {
		echo(req.Sql, resp)
		return
	}
	switch p := stmt.(type) {
	case *parser.ShowColumns:
		s.ShowColumns(p, req.Params, resp)
	case *parser.ShowDatabases:
		s.ShowDatabases(p, req.Params, resp)
	case *parser.ShowIndex:
		s.ShowIndex(p, req.Params, resp)
	case *parser.ShowTables:
		s.ShowTables(p, req.Params, resp)
	case *parser.Use:
		s.Use(p, req.Params, resp)
	default:
		echo(req.Sql, resp)
	}
}
예제 #19
0
// exec executes the request. Any error encountered is returned; it is
// the caller's responsibility to update the response.
func (e *Executor) execStmts(sql string, params parameters, planMaker *planner) driver.Response {
	var resp driver.Response
	stmts, err := parser.Parse(sql, parser.Syntax(planMaker.session.Syntax))
	if err != nil {
		// A parse error occurred: we can't determine if there were multiple
		// statements or only one, so just pretend there was one.
		resp.Results = append(resp.Results, makeResultFromError(planMaker, err))
		return resp
	}
	for _, stmt := range stmts {
		result, err := e.execStmt(stmt, params, planMaker)
		if err != nil {
			result = makeResultFromError(planMaker, err)
		}
		resp.Results = append(resp.Results, result)
		// TODO(pmattis): Is this the correct time to be releasing leases acquired
		// during execution of the statement?
		//
		// TODO(pmattis): Need to record the leases used by a transaction within
		// the transaction state and restore it when the transaction is restored.
		planMaker.releaseLeases(e.db)
	}
	return resp
}
예제 #20
0
func TestEvalExpr(t *testing.T) {
	testData := []struct {
		expr     string
		expected string
		env      Env
	}{
		// Bitwise operators.
		{`1 & 3`, `1`, nil},
		{`1 | 3`, `3`, nil},
		{`1 ^ 3`, `2`, nil},
		// Bitwise operators convert their arguments to ints.
		// TODO(pmattis): Should this be an error instead?
		{`1.1 ^ 3.1`, `2`, nil},
		// Arithmetic operators.
		{`1 + 1`, `2`, nil},
		{`1 - 2`, `-1`, nil},
		{`3 * 4`, `12`, nil},
		{`3.1 % 2.0`, `1.1`, nil},
		{`5 % 3`, `2`, nil},
		// Division is always done on floats.
		{`4 / 5`, `0.8`, nil},
		// Grouping
		{`1 + 2 + (3 * 4)`, `15`, nil},
		// Unary operators.
		{`-3`, `-3`, nil},
		{`-4.1`, `-4.1`, nil},
		// Ones complement operates on unsigned integers.
		{`~0`, `18446744073709551615`, nil},
		{`~0.1`, `18446744073709551615`, nil},
		{`~0 - 1`, `18446744073709551614`, nil},
		// Hexadecimal numbers.
		{`0xa`, `10`, nil},
		// Octal numbers.
		{`0755`, `493`, nil},
		// String conversion
		{`'1' + '2'`, `3`, nil},
		// Strings convert to floats.
		{`'18446744073709551614' + 1`, `1.8446744073709552e+19`, nil},
		// String concatenation.
		{`'a' || 'b'`, `ab`, nil},
		{`'a' || (1 + 2)`, `a3`, nil},
		// Column lookup.
		{`a`, `1`, mapEnv{"a": dInt(1)}},
		{`a`, `2`, mapEnv{"a": dUint(2)}},
		{`a`, `3.1`, mapEnv{"a": dFloat(3.1)}},
		{`a`, `b`, mapEnv{"a": dBytes([]byte("b"))}},
		{`a`, `c`, mapEnv{"a": dString("c")}},
		{`a.b + 1`, `2`, mapEnv{"a.b": dInt(1)}},
		// Boolean expressions.
		{`false AND true`, `false`, nil},
		{`true AND true`, `true`, nil},
		{`true AND false`, `false`, nil},
		{`false AND false`, `false`, nil},
		{`false OR true`, `true`, nil},
		{`true OR true`, `true`, nil},
		{`true OR false`, `true`, nil},
		{`false OR false`, `false`, nil},
		{`NOT false`, `true`, nil},
		{`NOT true`, `false`, nil},
		// Boolean expressions short-circuit the evaluation.
		{`false AND (a = 1)`, `false`, nil},
		{`true OR (a = 1)`, `true`, nil},
		// Comparisons.
		{`0 = 1`, `false`, nil},
		{`0 != 1`, `true`, nil},
		{`0 < 1`, `true`, nil},
		{`0 <= 1`, `true`, nil},
		{`0 > 1`, `false`, nil},
		{`0 >= 1`, `false`, nil},
		{`true = false`, `false`, nil},
		{`true != false`, `true`, nil},
		{`true < false`, `false`, nil},
		{`true <= false`, `false`, nil},
		{`true > false`, `true`, nil},
		{`true >= false`, `true`, nil},
		{`true <=> false`, `false`, nil},
		{`'a' = 'b'`, `false`, nil},
		{`'a' != 'b'`, `true`, nil},
		{`'a' < 'b'`, `true`, nil},
		{`'a' <= 'b'`, `true`, nil},
		{`'a' > 'b'`, `false`, nil},
		{`'a' >= 'b'`, `false`, nil},
		{`'a' >= 'b'`, `false`, nil},
		// Comparison of a string against a number compares using floating point.
		{`'10' > '2'`, `false`, nil},
		{`'10' > 2`, `true`, nil},
		// Comparisons against NULL result in NULL, except for the null-safe equal.
		{`0 = NULL`, `NULL`, nil},
		{`NULL = NULL`, `NULL`, nil},
		{`NULL <=> NULL`, `true`, nil},
		// NULL checks.
		{`0 IS NULL`, `false`, nil},
		{`0 IS NOT NULL`, `true`, nil},
		{`NULL IS NULL`, `true`, nil},
		{`NULL IS NOT NULL`, `false`, nil},
		// Range conditions.
		{`2 BETWEEN 1 AND 3`, `true`, nil},
		{`1 NOT BETWEEN 2 AND 3`, `true`, nil},
		{`'foo' BETWEEN 'a' AND 'z'`, `true`, nil},
		// Case operator.
		{`CASE WHEN true THEN 1 END`, `1`, nil},
		{`CASE WHEN false THEN 1 END`, `NULL`, nil},
		{`CASE WHEN false THEN 1 ELSE 2 END`, `2`, nil},
		{`CASE WHEN false THEN 1 WHEN false THEN 2 END`, `NULL`, nil},
	}
	for i, d := range testData {
		q, err := parser.Parse("SELECT " + d.expr)
		if err != nil {
			t.Fatalf("%d: %v: %s", i, err, d.expr)
		}
		expr := q.(*parser.Select).Exprs[0].(*parser.NonStarExpr).Expr
		r, err := EvalExpr(expr, d.env)
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		if s := r.String(); d.expected != s {
			t.Errorf("%d: expected %s, but found %s: %s", i, d.expected, s, d.expr)
		}
	}
}
예제 #21
0
// exec executes the request. Any error encountered is returned; it is
// the caller's responsibility to update the response.
func (s *Server) exec(req driver.Request) (resp driver.Response, err error) {

	// Pick up current session state.
	// The request user is validated in ServeHTTP. Even in insecure mode,
	// it is guaranteed not to be empty.
	planMaker := planner{user: req.GetUser()}
	defer func() {
		// Update session state even if an error occurs.
		if bytes, err := gogoproto.Marshal(&planMaker.session); err != nil {
			// Marshaling a `Session` never errors (known from reading the code).
			panic(err)
		} else {
			resp.Session = bytes
		}
	}()

	if req.Session != nil {
		// TODO(tschottdorf) will have to validate the Session information (for
		// instance, whether access to the stored database is permitted).
		if err = gogoproto.Unmarshal(req.Session, &planMaker.session); err != nil {
			return
		}
	}
	var stmts parser.StatementList
	if stmts, err = parser.Parse(req.Sql); err != nil {
		return
	}
	for _, stmt := range stmts {
		// Bind all the placeholder variables in the stmt to actual values.
		if err = parser.FillArgs(stmt, parameters(req.Params)); err != nil {
			return
		}
		var plan planNode
		if err = s.db.Txn(func(txn *client.Txn) error {
			planMaker.txn = txn
			plan, err = planMaker.makePlan(stmt)
			planMaker.txn = nil
			return err
		}); err != nil {
			return
		}

		result := driver.Result{
			Columns: plan.Columns(),
		}
		for plan.Next() {
			values := plan.Values()
			row := driver.Result_Row{}
			row.Values = make([]driver.Datum, 0, len(values))
			for _, val := range values {
				if val == parser.DNull {
					row.Values = append(row.Values, driver.Datum{})
				} else {
					switch vt := val.(type) {
					case parser.DBool:
						row.Values = append(row.Values, driver.Datum{BoolVal: (*bool)(&vt)})
					case parser.DInt:
						row.Values = append(row.Values, driver.Datum{IntVal: (*int64)(&vt)})
					case parser.DFloat:
						row.Values = append(row.Values, driver.Datum{FloatVal: (*float64)(&vt)})
					case parser.DString:
						row.Values = append(row.Values, driver.Datum{StringVal: (*string)(&vt)})
					default:
						err = util.Errorf("unsupported datum: %T", val)
						return
					}
				}
			}
			result.Rows = append(result.Rows, row)
		}
		if err = plan.Err(); err != nil {
			return
		}

		resp.Results = append(resp.Results, result)
	}

	return
}
예제 #22
0
func TestMakeTableDescIndexes(t *testing.T) {
	defer leaktest.AfterTest(t)

	testData := []struct {
		sql     string
		primary structured.IndexDescriptor
		indexes []structured.IndexDescriptor
	}{
		{
			"a INT PRIMARY KEY",
			structured.IndexDescriptor{
				Name:        structured.PrimaryKeyIndexName,
				Unique:      true,
				ColumnNames: []string{"a"},
			},
			[]structured.IndexDescriptor{},
		},
		{
			"a INT UNIQUE, b INT PRIMARY KEY",
			structured.IndexDescriptor{
				Name:        "primary",
				Unique:      true,
				ColumnNames: []string{"b"},
			},
			[]structured.IndexDescriptor{
				{
					Name:        "",
					Unique:      true,
					ColumnNames: []string{"a"},
				},
			},
		},
		{
			"a INT, b INT, CONSTRAINT c PRIMARY KEY (a, b)",
			structured.IndexDescriptor{
				Name:        "c",
				Unique:      true,
				ColumnNames: []string{"a", "b"},
			},
			[]structured.IndexDescriptor{},
		},
		{
			"a INT, b INT, CONSTRAINT c UNIQUE (b), PRIMARY KEY (a, b)",
			structured.IndexDescriptor{
				Name:        "primary",
				Unique:      true,
				ColumnNames: []string{"a", "b"},
			},
			[]structured.IndexDescriptor{
				{
					Name:        "c",
					Unique:      true,
					ColumnNames: []string{"b"},
				},
			},
		},
		{
			"a INT, b INT, PRIMARY KEY (a, b)",
			structured.IndexDescriptor{
				Name:        structured.PrimaryKeyIndexName,
				Unique:      true,
				ColumnNames: []string{"a", "b"},
			},
			[]structured.IndexDescriptor{},
		},
	}
	for i, d := range testData {
		stmt, err := parser.Parse("CREATE TABLE foo.test (" + d.sql + ")")
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		create := stmt[0].(*parser.CreateTable)
		if err := create.Table.NormalizeTableName(""); err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		schema, err := makeTableDesc(create)
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		if !reflect.DeepEqual(d.primary, schema.PrimaryIndex) {
			t.Fatalf("%d: expected %+v, but got %+v", i, d.primary, schema.PrimaryIndex)
		}
		if !reflect.DeepEqual(d.indexes, append([]structured.IndexDescriptor{}, schema.Indexes...)) {
			t.Fatalf("%d: expected %+v, but got %+v", i, d.indexes, schema.Indexes)
		}

	}
}
예제 #23
0
func TestMakeTableDescColumns(t *testing.T) {
	defer leaktest.AfterTest(t)

	testData := []struct {
		sqlType  string
		colType  structured.ColumnType
		nullable bool
	}{
		{
			"BIT(1)",
			structured.ColumnType{Kind: structured.ColumnType_BIT, Width: 1},
			true,
		},
		{
			"BOOLEAN",
			structured.ColumnType{Kind: structured.ColumnType_BOOL},
			true,
		},
		{
			"INT",
			structured.ColumnType{Kind: structured.ColumnType_INT},
			true,
		},
		{
			"FLOAT(3)",
			structured.ColumnType{Kind: structured.ColumnType_FLOAT, Precision: 3},
			true,
		},
		{
			"DECIMAL(5,6)",
			structured.ColumnType{Kind: structured.ColumnType_DECIMAL, Precision: 5, Width: 6},
			true,
		},
		{
			"DATE",
			structured.ColumnType{Kind: structured.ColumnType_DATE},
			true,
		},
		{
			"TIME",
			structured.ColumnType{Kind: structured.ColumnType_TIME},
			true,
		},
		{
			"TIMESTAMP",
			structured.ColumnType{Kind: structured.ColumnType_TIMESTAMP},
			true,
		},
		{
			"CHAR",
			structured.ColumnType{Kind: structured.ColumnType_CHAR},
			true,
		},
		{
			"TEXT",
			structured.ColumnType{Kind: structured.ColumnType_TEXT},
			true,
		},
		{
			"BLOB",
			structured.ColumnType{Kind: structured.ColumnType_BLOB},
			true,
		},
		{
			"INT NOT NULL",
			structured.ColumnType{Kind: structured.ColumnType_INT},
			false,
		},
		{
			"INT NULL",
			structured.ColumnType{Kind: structured.ColumnType_INT},
			true,
		},
	}
	for i, d := range testData {
		stmt, err := parser.Parse("CREATE TABLE foo.test (a " + d.sqlType + " PRIMARY KEY)")
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		create := stmt[0].(*parser.CreateTable)
		if err := create.Table.NormalizeTableName(""); err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		schema, err := makeTableDesc(create)
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		if !reflect.DeepEqual(d.colType, schema.Columns[0].Type) {
			t.Fatalf("%d: expected %+v, but got %+v", i, d.colType, schema.Columns[0])
		}
		if d.nullable != schema.Columns[0].Nullable {
			t.Fatalf("%d: expected %+v, but got %+v", i, d.nullable, schema.Columns[0].Nullable)
		}
	}
}
예제 #24
0
func TestMakeTableDescIndexes(t *testing.T) {
	defer leaktest.AfterTest(t)

	testData := []struct {
		sql   string
		index structured.IndexDescriptor
	}{
		{
			"a INT PRIMARY KEY",
			structured.IndexDescriptor{
				Name:        "primary",
				Unique:      true,
				ColumnNames: []string{"a"},
			},
		},
		{
			"a INT UNIQUE",
			structured.IndexDescriptor{
				Name:        "",
				Unique:      true,
				ColumnNames: []string{"a"},
			},
		},
		{
			"a INT, b INT, INDEX c (a, b)",
			structured.IndexDescriptor{
				Name:        "c",
				Unique:      false,
				ColumnNames: []string{"a", "b"},
			},
		},
		{
			"a INT, b INT, UNIQUE INDEX c (a, b)",
			structured.IndexDescriptor{
				Name:        "c",
				Unique:      true,
				ColumnNames: []string{"a", "b"},
			},
		},
		{
			"a INT, b INT, PRIMARY KEY (a, b)",
			structured.IndexDescriptor{
				Name:        "primary",
				Unique:      true,
				ColumnNames: []string{"a", "b"},
			},
		},
	}
	for i, d := range testData {
		stmt, err := parser.Parse("CREATE TABLE test (" + d.sql + ")")
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		schema, err := makeTableDesc(stmt.(*parser.CreateTable))
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		if !reflect.DeepEqual(d.index, schema.Indexes[0]) {
			t.Fatalf("%d: expected %+v, but got %+v", i, d.index, schema.Indexes[0])
		}
	}
}
예제 #25
0
func TestMakeTableDescColumns(t *testing.T) {
	defer leaktest.AfterTest(t)

	testData := []struct {
		sqlType  string
		colType  structured.ColumnType
		nullable bool
	}{
		{
			"BIT(1)",
			structured.ColumnType{Kind: structured.ColumnType_BIT, Width: 1},
			true,
		},
		{
			"INT(2)",
			structured.ColumnType{Kind: structured.ColumnType_INT, Width: 2},
			true,
		},
		{
			"FLOAT(3,4)",
			structured.ColumnType{Kind: structured.ColumnType_FLOAT, Width: 3, Precision: 4},
			true,
		},
		{
			"DECIMAL(5,6)",
			structured.ColumnType{Kind: structured.ColumnType_DECIMAL, Width: 5, Precision: 6},
			true,
		},
		{
			"DATE",
			structured.ColumnType{Kind: structured.ColumnType_DATE},
			true,
		},
		{
			"TIME",
			structured.ColumnType{Kind: structured.ColumnType_TIME},
			true,
		},
		{
			"DATETIME",
			structured.ColumnType{Kind: structured.ColumnType_DATETIME},
			true,
		},
		{
			"TIMESTAMP",
			structured.ColumnType{Kind: structured.ColumnType_TIMESTAMP},
			true,
		},
		{
			"CHAR",
			structured.ColumnType{Kind: structured.ColumnType_CHAR},
			true,
		},
		{
			"TEXT",
			structured.ColumnType{Kind: structured.ColumnType_TEXT},
			true,
		},
		{
			"BLOB",
			structured.ColumnType{Kind: structured.ColumnType_BLOB},
			true,
		},
		{
			"ENUM(a)",
			structured.ColumnType{Kind: structured.ColumnType_ENUM, Vals: []string{"a"}},
			true,
		},
		{
			"SET(b)",
			structured.ColumnType{Kind: structured.ColumnType_SET, Vals: []string{"b"}},
			true,
		},
		{
			"INT NOT NULL",
			structured.ColumnType{Kind: structured.ColumnType_INT},
			false,
		},
		{
			"INT NULL",
			structured.ColumnType{Kind: structured.ColumnType_INT},
			true,
		},
	}
	for i, d := range testData {
		stmt, err := parser.Parse("CREATE TABLE test (a " + d.sqlType + ")")
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		schema, err := makeTableDesc(stmt.(*parser.CreateTable))
		if err != nil {
			t.Fatalf("%d: %v", i, err)
		}
		if !reflect.DeepEqual(d.colType, schema.Columns[0].Type) {
			t.Fatalf("%d: expected %+v, but got %+v", i, d.colType, schema.Columns[0])
		}
		if d.nullable != schema.Columns[0].Nullable {
			t.Fatalf("%d: expected %+v, but got %+v", i, d.nullable, schema.Columns[0].Nullable)
		}
	}
}