# union
"select * from a union select * from b"
{
  "PlanID": "PASS_SELECT",
  "TableName": "",
  "FieldQuery": "select * from a where 1 != 1 union select * from b where 1 != 1",
  "FullQuery": "select * from a union select * from b limit :#maxLimit"
}

# union with limit
"select * from a union select * from b limit 10"
{
  "PlanID": "PASS_SELECT",
  "TableName": "",
  "FieldQuery": "select * from a where 1 != 1 union select * from b where 1 != 1",
  "FullQuery": "select * from a union select * from b limit 10"
}

# distinct
"select distinct * from a"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select * from a where 1 != 1",
  "FullQuery": "select distinct * from a limit :#maxLimit"
}

# grouy by
"select * from a group by b"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select * from a where 1 != 1 group by b",
  "FullQuery": "select * from a group by b limit :#maxLimit"
}

# having
"select * from a having b=1"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select * from a where 1 != 1",
  "FullQuery": "select * from a having b = 1 limit :#maxLimit"
}

# limit
"select * from a limit 5"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select * from a where 1 != 1",
  "FullQuery": "select * from a limit 5"
}

# limit with offset arg
"select * from a limit 10, 5"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select * from a where 1 != 1",
  "FullQuery": "select * from a limit 10, 5"
}

# limit with offset keyword
"select * from a limit 5 offset 10"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select * from a where 1 != 1",
  "FullQuery": "select * from a limit 10, 5"
}

# cross-db
"select * from a.b"
{
  "PlanID": "PASS_SELECT",
  "TableName": "",
  "FieldQuery": "select * from a.b where 1 != 1",
  "FullQuery": "select * from a.b limit :#maxLimit"
}

# multi-table
"select * from a,b"
{
  "PlanID": "PASS_SELECT",
  "TableName": "",
  "FieldQuery": "select * from a, b where 1 != 1",
  "FullQuery": "select * from a, b limit :#maxLimit"
}

# multi-table (join)
"select * from a join b"
{
  "PlanID": "PASS_SELECT",
  "TableName": "",
  "FieldQuery": "select * from a join b where 1 != 1",
  "FullQuery": "select * from a join b limit :#maxLimit"
}

# multi-table (right join)
"select * from a right join b on c = d"
{
  "PlanID": "PASS_SELECT",
  "TableName": "",
  "FieldQuery": "select * from a right join b on c = d where 1 != 1",
  "FullQuery": "select * from a right join b on c = d limit :#maxLimit"
}

# Parenthesized table
"select * from (b)"
{
  "PlanID": "PASS_SELECT",
  "TableName": "",
  "FieldQuery": "select * from (b) where 1 != 1",
  "FullQuery": "select * from (b) limit :#maxLimit"
}

# bind in select list
"select :bv from a"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FullQuery": "select :bv from a limit :#maxLimit"
}

# simple
"select eid from a"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select eid from a where 1 != 1",
  "FullQuery": "select eid from a limit :#maxLimit"
}

# as
"select eid as foo from a"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select eid as foo from a where 1 != 1",
  "FullQuery": "select eid as foo from a limit :#maxLimit"
}

# *
"select * from a"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select * from a where 1 != 1",
  "FullQuery": "select * from a limit :#maxLimit"
}

# c.eid
"select c.eid from a as c"
{
  "PlanID": "PASS_SELECT",
  "TableName": "a",
  "FieldQuery": "select c.eid from a as c where 1 != 1",
  "FullQuery": "select c.eid from a as c limit :#maxLimit"
}

# for update
"select eid from a for update"
{
  "PlanID": "SELECT_LOCK",
  "TableName": "a",
  "FieldQuery": "select eid from a where 1 != 1",
  "FullQuery": "select eid from a limit :#maxLimit for update"
}

# lock in share mode
"select eid from a lock in share mode"
{
  "PlanID": "SELECT_LOCK",
  "TableName": "a",
  "FieldQuery": "select eid from a where 1 != 1",
  "FullQuery": "select eid from a limit :#maxLimit lock in share mode"
}

# insert cross-db
"insert into b.a (eid, id) values (1, :a)"
{
  "PlanID": "PASS_DML",
  "Reason": "TABLE",
  "TableName": "",
  "FullQuery": "insert into b.a(eid, id) values (1, :a)"
}

# insert with bind value
"insert into a (eid, id) values (1, :a)"
{
  "PlanID": "INSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (1, :a)",
  "OuterQuery": "insert into a(eid, id) values (1, :a)",
  "PKValues": [1, ":a"]
}

# default number
"insert into a (id) values (1)"
{
  "PlanID": "INSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(id) values (1)",
  "OuterQuery": "insert into a(id) values (1)",
  "PKValues": [0, 1]
}

# default string
"insert into d(id) values(1)"
{
  "PlanID": "INSERT_PK",
  "TableName": "d",
  "FullQuery": "insert into d(id) values (1)",
  "OuterQuery": "insert into d(id) values (1)",
  "PKValues": ["0"]
}

# default without INTO
"insert d(id) values(1)"
{
  "PlanID": "INSERT_PK",
  "TableName": "d",
  "FullQuery": "insert into d(id) values (1)",
  "OuterQuery": "insert into d(id) values (1)",
  "PKValues": ["0"]
}

# mismatch
"insert into a (eid, id) values (1)"
"column count doesn't match value count"

# negative number
"insert into a (eid, id) values (-1, 2)"
{
  "PlanID": "INSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (-1, 2)",
  "OuterQuery": "insert into a(eid, id) values (-1, 2)",
  "PKValues": [-1, 2]
}

# positive number
"insert into a (eid, id) values (+1, 2)"
{
  "PlanID": "INSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (1, 2)",
  "OuterQuery": "insert into a(eid, id) values (1, 2)",
  "PKValues": [1, 2]
}

# non-trivial unary
"insert into a (eid, id) values (~1, 2)"
{
  "PlanID": "PASS_DML",
  "Reason": "COMPLEX_EXPR",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (~1, 2)"
}

# complex
"insert into a (eid, id) values (1+1, 2)"
{
  "PlanID": "PASS_DML",
  "Reason": "COMPLEX_EXPR",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (1 + 1, 2)"
}

# complex
"insert into a (eid, id) values (0x04, 2)"
{
  "PlanID": "PASS_DML",
  "Reason": "COMPLEX_EXPR",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (0x04, 2)"
}

# no index
"insert into c (eid, id) values (1, 2)"
{
  "PlanID": "PASS_DML",
  "Reason": "TABLE_NOINDEX",
  "TableName": "c",
  "FullQuery": "insert into c(eid, id) values (1, 2)"
}

# no column list
"insert into a values (1, 2)"
{
  "PlanID": "INSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a values (1, 2)",
  "OuterQuery": "insert into a values (1, 2)",
  "PKValues": [1, 2]
}

# on dup
"insert into b (eid, id) values (1, 2) on duplicate key update name = func(a)"
{
  "PlanID": "UPSERT_PK",
  "TableName": "b",
  "FullQuery": "insert into b(eid, id) values (1, 2) on duplicate key update name = func(a)",
  "OuterQuery": "insert into b(eid, id) values (1, 2)",
  "UpsertQuery": "update b set name = func(a) where :#pk",
  "PKValues": [1, 2]
}

# on dup pk change
"insert into b (eid, id) values (1, 2) on duplicate key update eid = 2"
{
  "PlanID": "UPSERT_PK",
  "TableName": "b",
  "FullQuery": "insert into b(eid, id) values (1, 2) on duplicate key update eid = 2",
  "OuterQuery": "insert into b(eid, id) values (1, 2)",
  "UpsertQuery": "update b set eid = 2 where :#pk",
  "PKValues": [1, 2],
  "SecondaryPKValues": [2, null]
}

# on dup, with values() func
"insert into a (eid, id, name) values (1, 2, 'foo') on duplicate key update name = values(name)"
{
  "PlanID": "UPSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id, name) values (1, 2, 'foo') on duplicate key update name = values(name)",
  "OuterQuery": "insert into a(eid, id, name) values (1, 2, 'foo')",
  "UpsertQuery": "update a set name = 'foo' where :#pk",
  "PKValues": [1, 2]
}

# on dup, with values() inside another func
"insert into a (eid, id, name) values (1, 2, 'foo') on duplicate key update name = concat(values(name), 'foo')"
{
  "PlanID": "UPSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id, name) values (1, 2, 'foo') on duplicate key update name = concat(values(name), 'foo')",
  "OuterQuery": "insert into a(eid, id, name) values (1, 2, 'foo')",
  "UpsertQuery": "update a set name = concat('foo', 'foo') where :#pk",
  "PKValues": [1, 2]
}

# on dup, with values() and simple expression
"insert into a (eid, id, name) values (1, 2, 3) on duplicate key update name = values(name) + 5"
{
  "PlanID": "UPSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id, name) values (1, 2, 3) on duplicate key update name = values(name) + 5",
  "OuterQuery": "insert into a(eid, id, name) values (1, 2, 3)",
  "UpsertQuery": "update a set name = 3 + 5 where :#pk",
  "PKValues": [1, 2]
}

# on dup, with values() and case expression
"insert into a (eid, id, name) values (1, 2, 3) on duplicate key update name = case when values(eid) < values(id) then values(name) + 5 else 3 end"
{
  "PlanID": "UPSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id, name) values (1, 2, 3) on duplicate key update name = case when values(eid) \u003c values(id) then values(name) + 5 else 3 end",
  "OuterQuery": "insert into a(eid, id, name) values (1, 2, 3)",
  "UpsertQuery": "update a set name = case when 1 \u003c 2 then 3 + 5 else 3 end where :#pk",
  "PKValues": [1, 2]
}

# on dup, with bindvars in values()
"insert into a (eid, id, name) values (1, :id, :name) on duplicate key update name = values(name), id = values(id)"
{
  "PlanID": "UPSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id, name) values (1, :id, :name) on duplicate key update name = values(name), id = values(id)",
  "OuterQuery": "insert into a(eid, id, name) values (1, :id, :name)",
  "UpsertQuery": "update a set name = :name, id = :id where :#pk",
  "PKValues": [1, ":id"],
  "SecondaryPKValues": [null, ":id"]
}

# complex upsert with values()
"insert into a (eid, id) values (1+1, 2) on duplicate key update eid = values(eid) + 1"
{
  "PlanID": "PASS_DML",
  "Reason": "COMPLEX_EXPR",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (1 + 1, 2) on duplicate key update eid = values(eid) + 1"
}


# upsert with mismatch values()
"insert into a (eid, id) values (1, 2) on duplicate key update eid  = values(eid), name = values(name)"
{
  "PlanID": "PASS_DML",
  "Reason": "UPSERT_COL_MISMATCH",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id) values (1, 2) on duplicate key update eid = values(eid), name = values(name)",
  "PKValues": [1, 2]
}

# on dup pk change, with values() func
"insert into b (eid, id) values (1, 2) on duplicate key update eid = values(eid), id = values(id)"
{
  "PlanID": "UPSERT_PK",
  "TableName": "b",
  "FullQuery": "insert into b(eid, id) values (1, 2) on duplicate key update eid = values(eid), id = values(id)",
  "OuterQuery": "insert into b(eid, id) values (1, 2)",
  "UpsertQuery": "update b set eid = 1, id = 2 where :#pk",
  "PKValues": [1, 2],
  "SecondaryPKValues": [1, 2]
}

# on dup pk change, with mixed expr and values() func
"insert into a (eid, id, name) values (1, 2, 'foo') on duplicate key update eid = 2, id = values(id), name = func()"
{
  "PlanID": "UPSERT_PK",
  "TableName": "a",
  "FullQuery": "insert into a(eid, id, name) values (1, 2, 'foo') on duplicate key update eid = 2, id = values(id), name = func()",
  "OuterQuery": "insert into a(eid, id, name) values (1, 2, 'foo')",
  "UpsertQuery": "update a set eid = 2, id = 2, name = func() where :#pk",
  "PKValues": [1, 2],
  "SecondaryPKValues": [2, 2]
}

# on dup complex pk change
"insert into b (id, eid) values (1, 2) on duplicate key update eid = func(a)"
{
  "PlanID": "PASS_DML",
  "Reason": "PK_CHANGE",
  "TableName": "b",
  "FullQuery": "insert into b(id, eid) values (1, 2) on duplicate key update eid = func(a)",
  "PKValues": [2, 1]
}

# on dup multi-row
"insert into b (id, eid) values (1, 2), (2, 3) on duplicate key update name = func(a)"
{
  "PlanID": "PASS_DML",
  "Reason": "UPSERT",
  "TableName": "b",
  "FullQuery": "insert into b(id, eid) values (1, 2), (2, 3) on duplicate key update name = func(a)",
  "PKValues": [[2,3],[1,2]]
}

# on dup subquery
"insert into b (id, eid) select * from a on duplicate key update name = func(a)"
{
  "PlanID": "PASS_DML",
  "Reason": "UPSERT",
  "TableName": "b",
  "FullQuery": "insert into b(id, eid) select * from a on duplicate key update name = func(a)"
}

# subquery
"insert into b (eid, id) select * from a"
{
  "PlanID": "INSERT_SUBQUERY",
  "TableName": "b",
  "FullQuery": "insert into b(eid, id) select * from a",
  "OuterQuery": "insert into b(eid, id) values :#values",
  "Subquery": "select * from a limit :#maxLimit",
  "ColumnNumbers": [0, 1],
  "SubqueryPKColumns": [0, 1]
}

# subquery with no column list
"insert into b select * from a"
{
  "PlanID": "INSERT_SUBQUERY",
  "TableName": "b",
  "FullQuery": "insert into b select * from a",
  "OuterQuery": "insert into b values :#values",
  "Subquery": "select * from a limit :#maxLimit",
  "ColumnNumbers": [0, 1],
  "SubqueryPKColumns": [0, 1]
}

# multi-row
"insert into b (eid, id) values (1, 2), (3, 4)"
{
  "PlanID": "INSERT_PK",
  "TableName": "b",
  "FullQuery": "insert into b(eid, id) values (1, 2), (3, 4)",
  "OuterQuery": "insert into b(eid, id) values (1, 2), (3, 4)",
  "PKValues": [[1, 3], [2, 4]]
}

# message insert with time_scheduled specified
"insert into msg(time_scheduled, id, message) values(1, 2, 'aa')"
{
  "PlanID": "INSERT_MESSAGE",
  "TableName": "msg",
  "FullQuery": "insert into msg(time_scheduled, id, message) values (1, 2, 'aa')",
  "OuterQuery": "insert into msg(time_scheduled, id, message, time_next, time_created, epoch) values (1, 2, 'aa', 1, :#time_now, 0)",
  "PKValues": [
    1,
    2
  ],
  "MessageReloaderQuery": "select time_next, epoch, id, message from msg where :#pk"
}

# message insert with no time_schedule
"insert into msg(id, message) values(2, 'aa')"
{
  "PlanID": "INSERT_MESSAGE",
  "TableName": "msg",
  "FullQuery": "insert into msg(id, message) values (2, 'aa')",
  "OuterQuery": "insert into msg(id, message, time_scheduled, time_next, time_created, epoch) values (2, 'aa', :#time_now, :#time_now, :#time_now, 0)",
  "PKValues": [
    ":#time_now",
    2
  ],
  "MessageReloaderQuery": "select time_next, epoch, id, message from msg where :#pk"
}

# message multi-value insert
"insert into msg(time_scheduled, id, message) values(1, 2, 'aa'), (3, 4, 'bb')"
{
  "PlanID": "INSERT_MESSAGE",
  "TableName": "msg",
  "FullQuery": "insert into msg(time_scheduled, id, message) values (1, 2, 'aa'), (3, 4, 'bb')",
  "OuterQuery": "insert into msg(time_scheduled, id, message, time_next, time_created, epoch) values (1, 2, 'aa', 1, :#time_now, 0), (3, 4, 'bb', 3, :#time_now, 0)",
  "PKValues": [
    [
      1,
      3
    ],
    [
      2,
      4
    ]
  ],
  "MessageReloaderQuery": "select time_next, epoch, id, message from msg where :#pk"
}

# message insert subquery
"insert into msg(time_scheduled, id, message) select * from a"
"subquery not allowed for message table: msg"

# message insert on dup key
"insert into msg(time_scheduled, id, message) Values(1, 2, 'aa') on duplicate key update message='bb'"
"'on duplicate key' construct not allowed for message table: msg"

# message insert without column list
"insert into msg values(1)"
"column list must be specified for message table insert: msg"

# message column count mismatch
"insert into msg(id, message) values(1)"
"column count doesn't match value count"

# message insert time_next
"insert into msg(id, message, time_next) values(2, 'aa', 3)"
"time_next must not be specified for message insert"

# message insert time_created
"insert into msg(id, message, time_created) values(2, 'aa', 3)"
"time_created must not be specified for message insert"

# message insert epoch
"insert into msg(id, message, epoch) values(2, 'aa', 3)"
"epoch must not be specified for message insert"

# message insert time_acked
"insert into msg(id, message, time_acked) values(2, 'aa', 3)"
"time_acked must not be specified for message insert"

# message insert id missing
"insert into msg(message) values('aa')"
"id must be specified for message insert"

# message insert message missing
"insert into msg(id) values(1)"
"message must be specified for message insert"

# update cross-db
"update b.a set name='foo' where eid=1 and id=1"
{
  "PlanID": "PASS_DML",
  "Reason": "TABLE",
  "TableName": "",
  "FullQuery": "update b.a set name = 'foo' where eid = 1 and id = 1"
}

# pk changed
"update b set eid=1"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "b",
  "FullQuery": "update b set eid = 1",
  "OuterQuery": "update b set eid = 1 where :#pk",
  "Subquery": "select eid, id from b limit :#maxLimit for update",
  "SecondaryPKValues": [1, null],
  "WhereClause": ""
}

# type mismatch
"update b set eid=18446744073709551616"
"type mismatch: strconv.ParseUint: parsing "18446744073709551616": value out of range"

# complex pk change
"update b set eid=foo()"
{
  "PlanID": "PASS_DML",
  "Reason": "PK_CHANGE",
  "TableName": "b",
  "FullQuery": "update b set eid = foo()",
  "WhereClause": ""
}

# update subquery
"update a set name='foo'"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo'",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "Subquery": "select eid, id from a limit :#maxLimit for update",
  "WhereClause": ""
}

# update complex where clause
"update a set name='foo' where eid+1=1"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo' where eid + 1 = 1",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "Subquery": "select eid, id from a where eid + 1 = 1 limit :#maxLimit for update",
  "WhereClause": " where eid + 1 = 1"
}

# pk
"update a set name='foo' where eid=1 and id=1"
{
  "PlanID": "DML_PK",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo' where eid = 1 and id = 1",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "PKValues": [1, 1],
  "WhereClause": " where eid = 1 and id = 1"
}

# partial pk
"update a set name='foo' where eid=1"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo' where eid = 1",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "Subquery": "select eid, id from a where eid = 1 limit :#maxLimit for update",
  "WhereClause": " where eid = 1"
}

# bad pk
"update a set name='foo' where eid=1.0 and id=1"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo' where eid = 1.0 and id = 1",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "Subquery": "select eid, id from a where eid = 1.0 and id = 1 limit :#maxLimit for update",
  "WhereClause": " where eid = 1.0 and id = 1"
}

# partial pk with limit
"update a set name='foo' where eid=1 limit 10"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo' where eid = 1 limit 10",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "Subquery": "select eid, id from a where eid = 1 limit 10 for update",
  "WhereClause": " where eid = 1"
}

# non-pk
"update a set name='foo' where eid=1 and name='foo'"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo' where eid = 1 and name = 'foo'",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "Subquery": "select eid, id from a where eid = 1 and name = 'foo' limit :#maxLimit for update",
  "WhereClause": " where eid = 1 and name = 'foo'"
}

# no index
"update c set eid=1"
{
  "PlanID": "PASS_DML",
  "Reason": "TABLE_NOINDEX",
  "TableName": "c",
  "FullQuery": "update c set eid = 1",
  "WhereClause": ""
}

# complex expression in where
"update a set name='foo' where eid+1=1 and id=1"
{
  "PlanID":"DML_SUBQUERY",
  "TableName":"a",
  "FullQuery":"update a set name = 'foo' where eid + 1 = 1 and id = 1",
  "OuterQuery":"update a set name = 'foo' where :#pk",
  "Subquery":"select eid, id from a where eid + 1 = 1 and id = 1 limit :#maxLimit for update",
  "WhereClause": " where eid + 1 = 1 and id = 1"
}

# parenthesized expressions in where
"update a set name='foo' where (eid=1) and id=1"
{
  "PlanID": "DML_PK",
  "TableName": "a",
  "FullQuery": "update a set name = 'foo' where (eid = 1) and id = 1",
  "OuterQuery": "update a set name = 'foo' where :#pk",
  "PKValues": [1, 1],
  "WhereClause": " where (eid = 1) and id = 1"
}

# in clause expression in where
"update a set name='foo' where eid in (1, 2) and id=1"
{
  "PlanID":"DML_PK",
  "TableName":"a",
  "FullQuery":"update a set name = 'foo' where eid in (1, 2) and id = 1",
  "OuterQuery":"update a set name = 'foo' where :#pk",
  "PKValues":[[1,2],1],
  "WhereClause": " where eid in (1, 2) and id = 1"
}

# double in clause
"update a set name='foo' where eid in (1, 2) and id in (1, 2)"
{
  "PlanID":"DML_SUBQUERY",
  "TableName":"a",
  "FullQuery":"update a set name = 'foo' where eid in (1, 2) and id in (1, 2)",
  "OuterQuery":"update a set name = 'foo' where :#pk",
  "Subquery":"select eid, id from a where eid in (1, 2) and id in (1, 2) limit :#maxLimit for update",
  "WhereClause": " where eid in (1, 2) and id in (1, 2)"
}

# double use of pk
"update a set name='foo' where eid=1 and eid=2"
{
  "PlanID":"DML_SUBQUERY",
  "TableName":"a",
  "FullQuery":"update a set name = 'foo' where eid = 1 and eid = 2",
  "OuterQuery":"update a set name = 'foo' where :#pk",
  "Subquery":"select eid, id from a where eid = 1 and eid = 2 limit :#maxLimit for update",
  "WhereClause": " where eid = 1 and eid = 2"
}

# delete cross-db
"delete from b.a where eid=1 and id=1"
{
  "PlanID": "PASS_DML",
  "Reason": "TABLE",
  "TableName": "",
  "FullQuery": "delete from b.a where eid = 1 and id = 1"
}

# delete with no where clause
"delete from a"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "delete from a",
  "OuterQuery": "delete from a where :#pk",
  "Subquery": "select eid, id from a limit :#maxLimit for update",
  "WhereClause": ""
}

# delete complex where clause
"delete from a where eid+1=1"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "delete from a where eid + 1 = 1",
  "OuterQuery": "delete from a where :#pk",
  "Subquery": "select eid, id from a where eid + 1 = 1 limit :#maxLimit for update",
  "WhereClause": " where eid + 1 = 1"
}

# pk
"delete from a where eid=1 and id=1"
{
  "PlanID": "DML_PK",
  "TableName": "a",
  "FullQuery": "delete from a where eid = 1 and id = 1",
  "OuterQuery": "delete from a where :#pk",
  "PKValues": [1, 1],
  "WhereClause": " where eid = 1 and id = 1"
}

# partial pk
"delete from a where eid=1"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "delete from a where eid = 1",
  "OuterQuery": "delete from a where :#pk",
  "Subquery": "select eid, id from a where eid = 1 limit :#maxLimit for update",
  "WhereClause": " where eid = 1"
}

# bad pk value delete
"delete from a where eid=1.0 and id=1"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "delete from a where eid = 1.0 and id = 1",
  "OuterQuery": "delete from a where :#pk",
  "Subquery": "select eid, id from a where eid = 1.0 and id = 1 limit :#maxLimit for update",
  "WhereClause": " where eid = 1.0 and id = 1"
}

# non-pk
"delete from a where eid=1 and name='foo'"
{
  "PlanID": "DML_SUBQUERY",
  "TableName": "a",
  "FullQuery": "delete from a where eid = 1 and name = 'foo'",
  "OuterQuery": "delete from a where :#pk",
  "Subquery": "select eid, id from a where eid = 1 and name = 'foo' limit :#maxLimit for update",
  "WhereClause": " where eid = 1 and name = 'foo'"
}

# no index
"delete from c"
{
  "PlanID": "PASS_DML",
  "Reason": "TABLE_NOINDEX",
  "TableName": "c",
  "FullQuery": "delete from c",
  "WhereClause": ""
}

# delete complex expression in where
"delete from a where eid+1=1 and id=1"
{
  "PlanID":"DML_SUBQUERY",
  "TableName":"a",
  "FullQuery":"delete from a where eid + 1 = 1 and id = 1",
  "OuterQuery":"delete from a where :#pk",
  "Subquery":"select eid, id from a where eid + 1 = 1 and id = 1 limit :#maxLimit for update",
  "WhereClause": " where eid + 1 = 1 and id = 1"
}

# parenthesized expressions in where
"delete from a where (eid=1) and id=1"
{
  "PlanID": "DML_PK",
  "TableName": "a",
  "FullQuery": "delete from a where (eid = 1) and id = 1",
  "OuterQuery": "delete from a where :#pk",
  "PKValues": [1, 1],
  "WhereClause": " where (eid = 1) and id = 1"
}

# delete in clause expression in where
"delete from a where eid in (1, 2) and id=1"
{
  "PlanID":"DML_PK",
  "TableName":"a",
  "FullQuery":"delete from a where eid in (1, 2) and id = 1",
  "OuterQuery":"delete from a where :#pk",
  "PKValues":[[1,2],1],
  "WhereClause": " where eid in (1, 2) and id = 1"
}

# delete double in clause
"delete from a where eid in (1, 2) and id in (1, 2)"
{
  "PlanID":"DML_SUBQUERY",
  "TableName":"a",
  "FullQuery":"delete from a where eid in (1, 2) and id in (1, 2)",
  "OuterQuery":"delete from a where :#pk",
  "Subquery":"select eid, id from a where eid in (1, 2) and id in (1, 2) limit :#maxLimit for update",
  "WhereClause": " where eid in (1, 2) and id in (1, 2)"
}

# delete double use of pk
"delete from a where eid=1 and eid=2"
{
  "PlanID":"DML_SUBQUERY",
  "TableName":"a",
  "FullQuery":"delete from a where eid = 1 and eid = 2",
  "OuterQuery":"delete from a where :#pk",
  "Subquery":"select eid, id from a where eid = 1 and eid = 2 limit :#maxLimit for update",
  "WhereClause": " where eid = 1 and eid = 2"
}

# single value sequence
"select next value from seq"
{
  "PlanID": "NEXTVAL",
  "TableName": "seq",
  "PKValues":[1]
}

# sequence with number
"select next 10 values from seq"
{
  "PlanID": "NEXTVAL",
  "TableName": "seq",
  "PKValues":[10]
}

# sequence with bindvar
"select next :a values from seq"
{
  "PlanID": "NEXTVAL",
  "TableName": "seq",
  "PKValues":[":a"]
}

# nextval on non-sequence table
"select next value from a"
"a is not a sequence"

# nextval on non-existent table
"select next value from id"
"table id not found in schema"

# int
"set  a=1"
{
  "PlanID": "SET",
  "TableName": "",
  "FullQuery": "set a = 1"
}

# float
"set  a=1.2"
{
  "PlanID": "SET",
  "TableName": "",
  "FullQuery": "set a = 1.2"
}

# string
"set a='b'"
{
  "PlanID": "SET",
  "TableName": "",
  "FullQuery": "set a = 'b'"
}

# multi
"set a=1, b=2"
{
  "PlanID": "SET",
  "TableName": "",
  "FullQuery": "set a = 1, b = 2"
}

# create
"create table a(a int, b varchar(8))"
{
  "PlanID": "DDL",
  "TableName": ""
}

# alter
"alter table a add column(a int)"
{
  "PlanID": "DDL",
  "TableName": "a"
}

# alter rename
"alter table a rename b"
{
  "PlanID": "DDL",
  "TableName": "a"
}

# rename
"rename table a to b"
{
  "PlanID": "DDL",
  "TableName": "a"
}

# drop
"drop table a"
{
  "PlanID": "DDL",
  "TableName": "a"
}

# analyze
"analyze table a"
{
  "PlanID": "DDL",
  "TableName": "a"
}

# show
"show a"
{
  "PlanID": "OTHER",
  "TableName": ""
}

# describe
"describe a"
{
  "PlanID": "OTHER",
  "TableName": ""
}

# explain
"explain a"
{
  "PlanID": "OTHER",
  "TableName": ""
}

# table not found select
"select * from aaaa"
"table aaaa not found in schema"

# table not found update
"update aaaa set a=1"
"table aaaa not found in schema"

# table not found update
"delete from aaaa"
"table aaaa not found in schema"

# table not found update
"insert into aaaa values(1)"
"table aaaa not found in schema"

# column not found insert with subquery
"insert into a(missing) select * from b"
"column missing not found in table a"

# syntax error
"syntax error"
"syntax error at position 7 near 'syntax'"
