1
0
Fork 0

Merge pull request #1333 from rqlite/add-empty-types

Fill in empty types using actual queried data
master
Philip O'Toole 1 year ago committed by GitHub
commit 84076f10ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,6 +2,7 @@
### Implementation changes and bug fixes
- [PR #1329](https://github.com/rqlite/rqlite/pull/1329): Try a different version of V2 Snapshot codec.
- [PR #1332](https://github.com/rqlite/rqlite/pull/1332): Upgrade dependencies.
- [PR #1333](https://github.com/rqlite/rqlite/pull/1333): Set "types" for expressions e.g. `COUNT`. Fixes [issue #1330](https://github.com/rqlite/rqlite/issues/1330)
## 7.21.2 (July 1st 2023)
### Implementation changes and bug fixes

@ -917,6 +917,7 @@ func (db *DB) queryStmtWithConn(stmt *command.Statement, xTime bool, q queryer)
for i := range types {
xTypes[i] = strings.ToLower(types[i].DatabaseTypeName())
}
needsQueryTypes := containsEmptyType(xTypes)
for rs.Next() {
dest := make([]interface{}, len(columns))
@ -934,6 +935,13 @@ func (db *DB) queryStmtWithConn(stmt *command.Statement, xTime bool, q queryer)
rows.Values = append(rows.Values, &command.Values{
Parameters: params,
})
// One-time population of any empty types. Best effort, ignore
// error.
if needsQueryTypes {
populateEmptyTypes(xTypes, params)
needsQueryTypes = false
}
}
// Check for errors from iterating over rows.
@ -1418,6 +1426,32 @@ func parametersToValues(parameters []*command.Parameter) ([]interface{}, error)
return values, nil
}
// populateEmptyTypes populates any empty types with the type of the parameter.
// This is necessary because the SQLite driver doesn't return the type of the
// column in some cases e.g. it's an expression, so we use the actual types
// of the returned data to fill in the blanks.
func populateEmptyTypes(types []string, params []*command.Parameter) error {
for i := range types {
if types[i] == "" {
switch params[i].GetValue().(type) {
case *command.Parameter_I:
types[i] = "integer"
case *command.Parameter_D:
types[i] = "real"
case *command.Parameter_B:
types[i] = "boolean"
case *command.Parameter_Y:
types[i] = "blob"
case *command.Parameter_S:
types[i] = "text"
default:
return fmt.Errorf("unsupported type: %T", params[i].GetValue())
}
}
}
return nil
}
// normalizeRowValues performs some normalization of values in the returned rows.
// Text values come over (from sqlite-go) as []byte instead of strings
// for some reason, so we have explicitly converted (but only when type
@ -1512,3 +1546,12 @@ func randomString() string {
}
return output.String()
}
func containsEmptyType(slice []string) bool {
for _, str := range slice {
if str == "" {
return true
}
}
return false
}

@ -90,7 +90,7 @@ func testNotNULLField(t *testing.T, db *DB) {
if err != nil {
t.Fatalf("failed to get PRAGMA table_info: %s", err.Error())
}
if exp, got := `[{"columns":["cid","name","type","notnull","dflt_value","pk"],"types":["","","","","",""],"values":[[0,"id","INTEGER",1,null,1],[1,"name","TEXT",0,null,0]]}]`, asJSON(r); exp != got {
if exp, got := `[{"columns":["cid","name","type","notnull","dflt_value","pk"],"types":["integer","text","text","integer","",""],"values":[[0,"id","INTEGER",1,null,1],[1,"name","TEXT",0,null,0]]}]`, asJSON(r); exp != got {
t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
}
}
@ -163,6 +163,64 @@ func testSimpleSingleStatements(t *testing.T, db *DB) {
}
}
// testSimpleExpressionStatements tests that types are set for expressions.
func testSimpleExpressionStatements(t *testing.T, db *DB) {
_, err := db.ExecuteStringStmt("CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT, age INTEGER, height REAL)")
if err != nil {
t.Fatalf("failed to create table: %s", err.Error())
}
_, err = db.ExecuteStringStmt(`INSERT INTO foo(id, name, age, height) VALUES(1, "fiona", 20, 6.7)`)
if err != nil {
t.Fatalf("failed to insert record: %s", err.Error())
}
_, err = db.ExecuteStringStmt(`INSERT INTO foo(id, name, age, height) VALUES(2, "aoife", 40, 10.4)`)
if err != nil {
t.Fatalf("failed to insert record: %s", err.Error())
}
tests := []struct {
query string
exp string
}{
{
query: `SELECT sum(name) FROM foo`,
exp: `[{"columns":["sum(name)"],"types":["real"],"values":[[0]]}]`,
},
{
query: `SELECT sum(age) FROM foo`,
exp: `[{"columns":["sum(age)"],"types":["integer"],"values":[[60]]}]`,
},
{
query: `SELECT sum(height) FROM foo`,
exp: `[{"columns":["sum(height)"],"types":["real"],"values":[[17.1]]}]`,
},
{
query: `SELECT count(*) FROM foo`,
exp: `[{"columns":["count(*)"],"types":["integer"],"values":[[2]]}]`,
},
{
query: `SELECT avg(height) FROM foo`,
exp: `[{"columns":["avg(height)"],"types":["real"],"values":[[8.55]]}]`,
},
{
query: `SELECT avg(height),count(*),sum(age) FROM foo`,
exp: `[{"columns":["avg(height)","count(*)","sum(age)"],"types":["real","integer","integer"],"values":[[8.55,2,60]]}]`,
},
}
for _, tt := range tests {
r, err := db.QueryStringStmt(tt.query)
if err != nil {
t.Fatalf("failed to query table: %s", err.Error())
}
if exp, got := tt.exp, asJSON(r); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}
}
func testSimpleSingleJSONStatements(t *testing.T, db *DB) {
_, err := db.ExecuteStringStmt("CREATE TABLE foo (c0 VARCHAR(36), c1 JSON, c2 NCHAR, c3 NVARCHAR, c4 CLOB)")
if err != nil {
@ -241,7 +299,7 @@ func testSimpleSingleConcatStatements(t *testing.T, db *DB) {
if err != nil {
t.Fatalf("failed to query table: %s", err.Error())
}
if exp, got := `[{"columns":["id || \"_bar\"","name"],"types":["","text"],"values":[["1_bar","fiona"]]}]`, asJSON(r); exp != got {
if exp, got := `[{"columns":["id || \"_bar\"","name"],"types":["text","text"],"values":[["1_bar","fiona"]]}]`, asJSON(r); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}
@ -409,7 +467,7 @@ func testSimplePragmaTableInfo(t *testing.T, db *DB) {
if err != nil {
t.Fatalf("failed to query a common table expression: %s", err.Error())
}
if exp, got := `[{"columns":["cid","name","type","notnull","dflt_value","pk"],"types":["","","","","",""],"values":[[0,"id","INTEGER",1,null,1],[1,"name","TEXT",0,null,0]]}]`, asJSON(res); exp != got {
if exp, got := `[{"columns":["cid","name","type","notnull","dflt_value","pk"],"types":["integer","text","text","integer","",""],"values":[[0,"id","INTEGER",1,null,1],[1,"name","TEXT",0,null,0]]}]`, asJSON(res); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}
@ -443,7 +501,7 @@ func testWriteOnQueryDatabaseShouldFail(t *testing.T, db *DB) {
if err != nil {
t.Fatalf("failed to query table: %s", err.Error())
}
if exp, got := `[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]`, asJSON(ro); exp != got {
if exp, got := `[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]`, asJSON(ro); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}
@ -776,7 +834,7 @@ func testSimpleRequest(t *testing.T, db *DB) {
`SELECT COUNT(*) FROM foo`,
`SELECT last FROM foo WHERE first="richard"`,
},
exp: `[{"last_insert_id":3,"rows_affected":1},{"columns":["COUNT(*)"],"types":[""],"values":[[3]]},{"columns":["last"],"types":["text"],"values":[["feynman"]]}]`,
exp: `[{"last_insert_id":3,"rows_affected":1},{"columns":["COUNT(*)"],"types":["integer"],"values":[[3]]},{"columns":["last"],"types":["text"],"values":[["feynman"]]}]`,
},
{
name: "insert and select non-existent table",
@ -785,7 +843,7 @@ func testSimpleRequest(t *testing.T, db *DB) {
`SELECT COUNT(*) FROM foo`,
`SELECT * FROM bar`,
},
exp: `[{"last_insert_id":4,"rows_affected":1},{"columns":["COUNT(*)"],"types":[""],"values":[[4]]},{"error":"no such table: bar"}]`,
exp: `[{"last_insert_id":4,"rows_affected":1},{"columns":["COUNT(*)"],"types":["integer"],"values":[[4]]},{"error":"no such table: bar"}]`,
},
}
@ -1142,21 +1200,21 @@ func testJSON1(t *testing.T, db *DB) {
if err != nil {
t.Fatalf("failed to perform simple SELECT: %s", err.Error())
}
if exp, got := `[{"columns":["phone"],"types":[""],"values":[["{\"mobile\":\"789111\",\"home\":\"123456\"}"]]}]`, asJSON(q); exp != got {
if exp, got := `[{"columns":["phone"],"types":["text"],"values":[["{\"mobile\":\"789111\",\"home\":\"123456\"}"]]}]`, asJSON(q); exp != got {
t.Fatalf("unexpected results for simple query, expected %s, got %s", exp, got)
}
q, err = db.QueryStringStmt("SELECT json_extract(customer.phone, '$.mobile') FROM customer")
if err != nil {
t.Fatalf("failed to perform simple SELECT: %s", err.Error())
}
if exp, got := `[{"columns":["json_extract(customer.phone, '$.mobile')"],"types":[""],"values":[["789111"]]}]`, asJSON(q); exp != got {
if exp, got := `[{"columns":["json_extract(customer.phone, '$.mobile')"],"types":["text"],"values":[["789111"]]}]`, asJSON(q); exp != got {
t.Fatalf("unexpected results for JSON query, expected %s, got %s", exp, got)
}
q, err = db.QueryStringStmt("SELECT customer.phone ->> '$.mobile' FROM customer")
if err != nil {
t.Fatalf("failed to perform simple SELECT: %s", err.Error())
}
if exp, got := `[{"columns":["customer.phone ->> '$.mobile'"],"types":[""],"values":[["789111"]]}]`, asJSON(q); exp != got {
if exp, got := `[{"columns":["customer.phone ->> '$.mobile'"],"types":["text"],"values":[["789111"]]}]`, asJSON(q); exp != got {
t.Fatalf("unexpected results for JSON query, expected %s, got %s", exp, got)
}
}
@ -1308,6 +1366,7 @@ func Test_DatabaseCommonOperations(t *testing.T) {
{"NotNULLField", testNotNULLField},
{"EmptyStatements", testEmptyStatements},
{"SimpleSingleStatements", testSimpleSingleStatements},
{"SimpleExpressionStatements", testSimpleExpressionStatements},
{"SimpleSingleJSONStatements", testSimpleSingleJSONStatements},
{"SimpleJoinStatements", testSimpleJoinStatements},
{"SimpleSingleConcatStatements", testSimpleSingleConcatStatements},

@ -150,7 +150,7 @@ func Test_DeserializeIntoMemory(t *testing.T) {
if err != nil {
t.Fatalf("failed to query table: %s", err.Error())
}
if exp, got := `[{"columns":["COUNT(*)"],"types":[""],"values":[[5004]]}]`, asJSON(ro); exp != got {
if exp, got := `[{"columns":["COUNT(*)"],"types":["integer"],"values":[[5004]]}]`, asJSON(ro); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}

@ -126,7 +126,7 @@ func Test_ConcurrentQueriesInMemory(t *testing.T) {
if err != nil {
t.Logf("failed to query table: %s", err.Error())
}
if exp, got := `[{"columns":["COUNT(*)"],"types":[""],"values":[[5000]]}]`, asJSON(ro); exp != got {
if exp, got := `[{"columns":["COUNT(*)"],"types":["integer"],"values":[[5000]]}]`, asJSON(ro); exp != got {
t.Logf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}()

@ -429,7 +429,7 @@ func Test_SingleNodeInMemRequest(t *testing.T) {
`INSERT INTO foo(id, name) VALUES(77, "fiona")`,
`SELECT COUNT(*) FROM foo`,
},
expected: `[{"last_insert_id":77,"rows_affected":1},{"columns":["COUNT(*)"],"types":[""],"values":[[3]]}]`,
expected: `[{"last_insert_id":77,"rows_affected":1},{"columns":["COUNT(*)"],"types":["integer"],"values":[[3]]}]`,
},
{
stmts: []string{
@ -438,7 +438,7 @@ func Test_SingleNodeInMemRequest(t *testing.T) {
`SELECT COUNT(*) FROM foo WHERE name='fiona'`,
`SELECT * FROM foo WHERE name='declan'`,
},
expected: `[{"last_insert_id":88,"rows_affected":1,"rows":null},{"error":"near \"nonsense\": syntax error"},{"types":{"COUNT(*)":""},"rows":[{"COUNT(*)":3}]},{"types":{"id":"integer","name":"text"},"rows":[{"id":66,"name":"declan"}]}]`,
expected: `[{"last_insert_id":88,"rows_affected":1,"rows":null},{"error":"near \"nonsense\": syntax error"},{"types":{"COUNT(*)":"integer"},"rows":[{"COUNT(*)":3}]},{"types":{"id":"integer","name":"text"},"rows":[{"id":66,"name":"declan"}]}]`,
associative: true,
},
}
@ -517,7 +517,7 @@ func Test_SingleNodeInMemRequestTx(t *testing.T) {
stmts: []string{
`SELECT COUNT(*) FROM foo`,
},
expected: `[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]`,
expected: `[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]`,
},
}

@ -167,7 +167,6 @@ COMMIT;
t.Fatalf("Backup Failed: unable to create temp file, %s", err.Error())
}
defer os.Remove(f.Name())
t.Logf("backup file is %s", f.Name())
if err := s.Backup(backupRequestBinary(true), f); err != nil {
t.Fatalf("Backup failed %s", err.Error())

@ -141,7 +141,7 @@ func openStoreCloseStartup(t *testing.T, s *Store) {
if err != nil {
t.Fatalf("failed to query single node: %s", err.Error())
}
if exp, got := `[{"columns":["COUNT(*)"],"types":[""],"values":[[10]]}]`, asJSON(r); exp != got {
if exp, got := `[{"columns":["COUNT(*)"],"types":["integer"],"values":[[10]]}]`, asJSON(r); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
@ -169,7 +169,7 @@ func openStoreCloseStartup(t *testing.T, s *Store) {
if err != nil {
t.Fatalf("failed to query single node: %s", err.Error())
}
if exp, got := `[{"columns":["COUNT(*)"],"types":[""],"values":[[11]]}]`, asJSON(r); exp != got {
if exp, got := `[{"columns":["COUNT(*)"],"types":["integer"],"values":[[11]]}]`, asJSON(r); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
@ -201,7 +201,7 @@ func openStoreCloseStartup(t *testing.T, s *Store) {
if err != nil {
t.Fatalf("failed to query single node: %s", err.Error())
}
if exp, got := `[{"columns":["COUNT(*)"],"types":[""],"values":[[11]]}]`, asJSON(r); exp != got {
if exp, got := `[{"columns":["COUNT(*)"],"types":["integer"],"values":[[11]]}]`, asJSON(r); exp != got {
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
}
}

@ -202,7 +202,7 @@ func Test_MultiNodeClusterRANDOM(t *testing.T) {
if err != nil {
t.Fatalf("failed to query for count: %s", err.Error())
}
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]}`; got != exp {
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]}`; got != exp {
t.Fatalf("wrong query results, exp %s, got %s", exp, got)
}
@ -830,7 +830,7 @@ func Test_MultiNodeClusterQueuedWrites(t *testing.T) {
}()
wg.Wait()
exp := fmt.Sprintf(`{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[%d]]}]}`, numLoops*writesPerLoop)
exp := fmt.Sprintf(`{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[%d]]}]}`, numLoops*writesPerLoop)
got, err := node1.Query(`SELECT COUNT(*) FROM foo`)
if err != nil {
t.Fatalf("failed to query follower node: %s", err.Error())
@ -900,7 +900,7 @@ func Test_MultiNodeClusterLargeQueuedWrites(t *testing.T) {
}
wg.Wait()
exp := fmt.Sprintf(`{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[%d]]}]}`, len(nodesUnderTest)*writesPerNode)
exp := fmt.Sprintf(`{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[%d]]}]}`, len(nodesUnderTest)*writesPerNode)
got, err := node1.Query(`SELECT COUNT(*) FROM foo`)
if err != nil {
t.Fatalf("failed to query follower node: %s", err.Error())
@ -1185,7 +1185,7 @@ func Test_MultiNodeClusterSnapshot(t *testing.T) {
t.Fatalf("failed to query follower node: %s", err.Error())
}
if r != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[300]]}]}` {
if r != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[300]]}]}` {
if n < 20 {
// Wait, and try again.
time.Sleep(mustParseDuration("1s"))
@ -1217,7 +1217,7 @@ func Test_MultiNodeClusterSnapshot(t *testing.T) {
t.Fatalf("failed to query follower node: %s", err.Error())
}
if r != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[300]]}]}` {
if r != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[300]]}]}` {
if n < 10 {
// Wait, and try again.
time.Sleep(mustParseDuration("100ms"))
@ -1381,7 +1381,7 @@ func Test_MultiNodeClusterRecoverSingle(t *testing.T) {
if _, err := node1.Execute(`INSERT INTO foo(id, name) VALUES(1, "fiona")`); err != nil {
t.Fatalf("failed to create table: %s", err.Error())
}
if rows, _ := node1.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]}` {
if rows, _ := node1.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]}` {
t.Fatalf("got incorrect results from node: %s", rows)
}
@ -1439,7 +1439,7 @@ func Test_MultiNodeClusterRecoverSingle(t *testing.T) {
if err != nil {
t.Fatalf("failed waiting for leader: %s", err.Error())
}
if rows, _ := okSingle.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]}` {
if rows, _ := okSingle.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]}` {
t.Fatalf("got incorrect results from recovered node: %s", rows)
}
okSingle.Close(true)
@ -1484,7 +1484,7 @@ func Test_MultiNodeClusterRecoverFull(t *testing.T) {
if _, err := node1.Execute(`INSERT INTO foo(id, name) VALUES(1, "fiona")`); err != nil {
t.Fatalf("failed to create table: %s", err.Error())
}
if rows, _ := node1.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]}` {
if rows, _ := node1.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]}` {
t.Fatalf("got incorrect results from node: %s", rows)
}
@ -1532,7 +1532,7 @@ func Test_MultiNodeClusterRecoverFull(t *testing.T) {
t.Fatalf("failed waiting for leader on recovered cluster: %s", err.Error())
}
if rows, _ := node4.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]}` {
if rows, _ := node4.Query(`SELECT COUNT(*) FROM foo`); rows != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]}` {
t.Fatalf("got incorrect results from recovered node: %s", rows)
}
}

@ -160,7 +160,7 @@ class TestJoinCatchup(unittest.TestCase):
j = n0.execute('INSERT INTO foo(name) VALUES("fiona")')
self.assertEqual(j, d_("{'results': [{'last_insert_id': 2, 'rows_affected': 1}]}"))
j = n0.query('SELECT COUNT(*) FROM foo')
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': [''], 'columns': ['COUNT(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': ['integer'], 'columns': ['COUNT(*)']}]}"))
applied = n0.wait_for_all_fsm()
# Restart follower, explicity rejoin, and ensure it picks up new records
@ -169,7 +169,7 @@ class TestJoinCatchup(unittest.TestCase):
self.n1.wait_for_fsm_index(applied)
self.assertEqual(n0.expvar()['store']['num_ignored_joins'], 1)
j = self.n1.query('SELECT COUNT(*) FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': [''], 'columns': ['COUNT(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': ['integer'], 'columns': ['COUNT(*)']}]}"))
def test_change_addresses(self):
'''Test that a node rejoining with new addresses works fine'''
@ -192,7 +192,7 @@ class TestJoinCatchup(unittest.TestCase):
j = n0.execute('INSERT INTO foo(name) VALUES("fiona")')
self.assertEqual(j, d_("{'results': [{'last_insert_id': 2, 'rows_affected': 1}]}"))
j = n0.query('SELECT COUNT(*) FROM foo')
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': [''], 'columns': ['COUNT(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': ['integer'], 'columns': ['COUNT(*)']}]}"))
applied = n0.wait_for_all_fsm()
# Restart follower with new network attributes, explicity rejoin, and ensure it picks up new records
@ -202,7 +202,7 @@ class TestJoinCatchup(unittest.TestCase):
self.assertEqual(n0.expvar()['store']['num_removed_before_joins'], 1)
self.n1.wait_for_fsm_index(applied)
j = self.n1.query('SELECT COUNT(*) FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': [''], 'columns': ['COUNT(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[2]], 'types': ['integer'], 'columns': ['COUNT(*)']}]}"))
if __name__ == "__main__":
unittest.main(verbosity=2)

@ -333,7 +333,7 @@ class TestRequestForwarding(unittest.TestCase):
# Data should be ready immediately, since we waited.
j = l.query('SELECT COUNT(*) FROM foo')
self.assertEqual(j, d_("{'results': [{'columns': ['COUNT(*)'], 'types': [''], 'values': [[2002]]}]}"))
self.assertEqual(j, d_("{'results': [{'columns': ['COUNT(*)'], 'types': ['integer'], 'values': [[2002]]}]}"))
class TestEndToEndNonVoter(unittest.TestCase):
def setUp(self):
@ -556,11 +556,11 @@ class TestEndToEndSnapRestoreCluster(unittest.TestCase):
# Ensure those new nodes have the full correct state.
self.n1.wait_for_fsm_index(self.n0.fsm_index())
j = self.n1.query('SELECT count(*) FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[201]], 'types': [''], 'columns': ['count(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[201]], 'types': ['integer'], 'columns': ['count(*)']}]}"))
self.n2.wait_for_fsm_index(self.n0.fsm_index())
j = self.n2.query('SELECT count(*) FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[201]], 'types': [''], 'columns': ['count(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[201]], 'types': ['integer'], 'columns': ['count(*)']}]}"))
# Kill one of the nodes, and make more changes, enough to trigger more snaps.
self.n2.stop()
@ -590,7 +590,7 @@ class TestEndToEndSnapRestoreCluster(unittest.TestCase):
if t > TIMEOUT:
raise Exception('timeout waiting for n2 to have all data')
j = self.n2.query('SELECT count(*) FROM foo', level='none')
if j == d_("{'results': [{'values': [[402]], 'types': [''], 'columns': ['count(*)']}]}"):
if j == d_("{'results': [{'values': [[402]], 'types': ['integer'], 'columns': ['count(*)']}]}"):
break
time.sleep(1)
t+=1

@ -229,7 +229,7 @@ class TestEndToEndSnapRestoreSingle(unittest.TestCase):
# Ensure node has the full correct state.
j = self.n0.query('SELECT count(*) FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[200]], 'types': [''], 'columns': ['count(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[200]], 'types': ['integer'], 'columns': ['count(*)']}]}"))
# Restart node, and make sure it comes back with the correct state
self.n0.stop()
@ -239,7 +239,7 @@ class TestEndToEndSnapRestoreSingle(unittest.TestCase):
self.assertEqual(self.n0.expvar()['store']['num_restores'], 1)
j = self.n0.query('SELECT count(*) FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[200]], 'types': [''], 'columns': ['count(*)']}]}"))
self.assertEqual(j, d_("{'results': [{'values': [[200]], 'types': ['integer'], 'columns': ['count(*)']}]}"))
def tearDown(self):
deprovision_node(self.n0)

@ -239,7 +239,7 @@ func Test_MultiNodeClusterRequestForwardOK(t *testing.T) {
if err != nil {
t.Fatalf("failed to create table: %s", err.Error())
}
if exp, got := `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[3]]}]}`, rows; exp != got {
if exp, got := `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[3]]}]}`, rows; exp != got {
t.Fatalf("got incorrect response from follower exp: %s, got: %s", exp, got)
}
}
@ -279,7 +279,7 @@ func Test_MultiNodeClusterQueuedRequestForwardOK(t *testing.T) {
if err != nil {
t.Fatalf("failed to query for count: %s", err.Error())
}
if exp, got := `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[0]]}]}`, rows; exp != got {
if exp, got := `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[0]]}]}`, rows; exp != got {
t.Fatalf("got incorrect response from follower exp: %s, got: %s", exp, got)
}
@ -305,7 +305,7 @@ func Test_MultiNodeClusterQueuedRequestForwardOK(t *testing.T) {
if err != nil {
t.Fatalf("failed to query for count: %s", err.Error())
}
if r == `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[1]]}]}` {
if r == `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[1]]}]}` {
return
}
case <-timer.C:

@ -294,7 +294,7 @@ func Test_SingleNodeConcurrentRequests(t *testing.T) {
if err != nil {
t.Fatalf("failed to count records: %s", err.Error())
}
if r != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[200]]}]}` {
if r != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[200]]}]}` {
t.Fatalf("test received wrong result got %s", r)
}
}
@ -327,7 +327,7 @@ func Test_SingleNodeConcurrentRequestsCompressed(t *testing.T) {
if err != nil {
t.Fatalf("failed to count records: %s", err.Error())
}
if r != `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[200]]}]}` {
if r != `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[200]]}]}` {
t.Fatalf("test received wrong result got %s", r)
}
}
@ -568,7 +568,7 @@ LOOP:
if err != nil {
t.Fatalf(`query failed: %s`, err.Error())
}
if r == `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[3]]}]}` {
if r == `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[3]]}]}` {
break LOOP
}
case <-timer.C:
@ -590,7 +590,7 @@ LOOP:
if err != nil {
t.Fatalf(`query failed: %s`, err.Error())
}
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[6]]}]}`; got != exp {
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[6]]}]}`; got != exp {
t.Fatalf("incorrect results, exp: %s, got: %s", exp, got)
}
}
@ -633,7 +633,7 @@ LOOP1:
if err != nil {
t.Fatalf(`query failed: %s`, err.Error())
}
if r == `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[2]]}]}` {
if r == `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[2]]}]}` {
break LOOP1
}
case <-timer.C:
@ -662,7 +662,7 @@ LOOP2:
if err != nil {
t.Fatalf(`query failed: %s`, err.Error())
}
if r == `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[2]]}]}` {
if r == `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[2]]}]}` {
break LOOP2
}
case <-timer.C:
@ -707,7 +707,7 @@ func Test_SingleNodeQueuedEmptyNil(t *testing.T) {
if err != nil {
t.Fatalf(`query failed: %s`, err.Error())
}
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[3]]}]}`; got != exp {
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[3]]}]}`; got != exp {
t.Fatalf("incorrect results, exp: %s, got: %s", exp, got)
}
@ -732,7 +732,7 @@ func Test_SingleNodeQueuedEmptyNil(t *testing.T) {
if err != nil {
t.Fatalf(`query failed: %s`, err.Error())
}
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[6]]}]}`; got != exp {
if got, exp := r, `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[6]]}]}`; got != exp {
t.Fatalf("incorrect results, exp: %s, got: %s", exp, got)
}
}
@ -888,7 +888,7 @@ func Test_SingleNodeUpgrades(t *testing.T) {
if err != nil {
t.Fatalf("query failed with %s data: %s", dir, err)
}
expected := `{"results":[{"columns":["COUNT(*)"],"types":[""],"values":[[20]]}]}`
expected := `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[20]]}]}`
if r == expected {
close(testSuccess)
}

Loading…
Cancel
Save