Commit c6442256 authored by Geofrey Ernest's avatar Geofrey Ernest

Evaluate field expression when selecting on dummy tables

This commit ensures the field expression is evaluated when selecting from nothing.

For instance you can

```
select 10, now();
```

This query will return a row of two values, 10 and `time.Time`.

This functionality is handy when we try to implement the pg_sleep function to slow down queries.

so we can do something like

```
select 1;select sleep(100);select 2;
 ```
parent 109b5f7b
......@@ -3504,69 +3504,117 @@ COMMIT;
}
func TestSelectDummy(t *testing.T) {
RegisterMemDriver()
db, err := sql.Open("ql-mem", "")
db, err := OpenMem()
if err != nil {
t.Fatal(err)
}
defer db.Close()
//int
var i int
err = db.QueryRow("select 1").Scan(&i)
if err != nil {
t.Fatal(err)
}
if i != 1 {
t.Fatalf("expected 1 got %d", i)
}
i = 0
err = db.QueryRow("select $1", 1).Scan(&i)
if err != nil {
t.Fatal(err)
}
if i != 1 {
t.Fatalf("expected 1 got %d", i)
}
//float
var f float64
err = db.QueryRow("select 1.5").Scan(&f)
if err != nil {
t.Fatal(err)
sample := []struct {
src string
exp []interface{}
}{
{"select 10", []interface{}{10}},
{"select 10,20", []interface{}{10, 20}},
}
if f != 1.5 {
t.Fatalf("expected 1.0 got %f", f)
for _, s := range sample {
rst, _, err := db.run(nil, s.src)
if err != nil {
t.Fatal(err)
}
for _, rs := range rst {
d, err := rs.FirstRow()
if err != nil {
t.Fatal(err)
}
for k, val := range d {
if int(val.(idealInt)) != s.exp[k].(int) {
t.Errorf("expected %v got %v", s.exp[k], val)
}
}
}
}
f = 0.0
err = db.QueryRow("select $1", 1.5).Scan(&f)
if err != nil {
t.Fatal(err)
// //float
sample = []struct {
src string
exp []interface{}
}{
{"select 1.5", []interface{}{1.5}},
{"select 1.5,2.5", []interface{}{1.5, 2.5}},
}
if f != 1.5 {
t.Fatalf("expected 1.5 got %f", f)
for _, s := range sample {
rst, _, err := db.run(nil, s.src)
if err != nil {
t.Fatal(err)
}
for _, rs := range rst {
d, err := rs.FirstRow()
if err != nil {
t.Fatal(err)
}
for k, val := range d {
if float64(val.(idealFloat)) != s.exp[k].(float64) {
t.Errorf("expected %v got %v", s.exp[k], val)
}
}
}
}
//string
var s string
msg := "foo"
err = db.QueryRow(`select "foo"`).Scan(&s)
if err != nil {
t.Fatal(err)
// //string
sample = []struct {
src string
exp []interface{}
}{
{`select "foo"`, []interface{}{"foo"}},
{`select "foo","bar"`, []interface{}{"foo", "bar"}},
}
if s != msg {
t.Fatalf("expected %s got %s", msg, s)
for _, s := range sample {
rst, _, err := db.run(nil, s.src)
if err != nil {
t.Fatal(err)
}
for _, rs := range rst {
d, err := rs.FirstRow()
if err != nil {
t.Fatal(err)
}
for k, val := range d {
if val.(string) != s.exp[k].(string) {
t.Errorf("expected %v got %v", s.exp[k], val)
}
}
}
}
s = ""
err = db.QueryRow("select $1", msg).Scan(&s)
if err != nil {
t.Fatal(err)
sample = []struct {
src string
exp []interface{}
}{
{`select "foo",now()`, []interface{}{"foo"}},
}
if s != msg {
t.Fatalf("expected %s got %s", msg, s)
for _, s := range sample {
rst, _, err := db.run(nil, s.src)
if err != nil {
t.Fatal(err)
}
for _, rs := range rst {
d, err := rs.FirstRow()
if err != nil {
t.Fatal(err)
}
for k, val := range d {
if k == 1 {
if _, ok := val.(time.Time); !ok {
t.Fatal("expected time object")
}
continue
}
if val.(string) != s.exp[k].(string) {
t.Errorf("expected %v got %v", s.exp[k], val)
}
}
}
}
}
......
......@@ -2801,7 +2801,7 @@ func (r *fullJoinDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []int
}
type selectDummyPlan struct {
fields []interface{}
flds []*fld
}
func (r *selectDummyPlan) hasID() bool { return true }
......@@ -2810,13 +2810,22 @@ func (r *selectDummyPlan) explain(w strutil.Formatter) {
w.Format("┌Selects values from dummy table\n└Output field names %v\n", qnames(r.fieldNames()))
}
func (r *selectDummyPlan) fieldNames() []string { return make([]string, len(r.fields)) }
func (r *selectDummyPlan) fieldNames() []string { return make([]string, len(r.flds)) }
func (r *selectDummyPlan) filter(expr expression) (plan, []string, error) {
return nil, nil, nil
}
func (r *selectDummyPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) {
_, err = f(nil, r.fields)
m := map[interface{}]interface{}{}
data := []interface{}{}
for _, v := range r.flds {
rst, err := v.expr.eval(ctx, m)
if err != nil {
return err
}
data = append(data, rst)
}
_, err = f(nil, data)
return
}
......@@ -803,13 +803,7 @@ func (s *selectStmt) plan(ctx *execCtx) (plan, error) { //LATER overlapping goro
}
}
if r == nil {
var fds []interface{}
for _, v := range s.flds {
if val, ok := v.expr.(value); ok {
fds = append(fds, val)
}
}
r = &selectDummyPlan{fields: fds}
r = &selectDummyPlan{flds: s.flds}
}
if w := s.where; w != nil {
if r, err = (&whereRset{expr: w.expr, src: r, sel: w.sel, exists: w.exists}).plan(ctx); err != nil {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment