mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
* ID sql3 internal type representation is int64; fixed a bug that assumed incorrectly that it wasn't * refactored some names for clarity * primary: get nested loop joins to work; secondary get brute force aggregations for SUM working * added tests; removed debug output * review feedback * Update sql3/planner/compileselect.go review feedback Co-authored-by: Travis Turner <travis@pilosa.com> Co-authored-by: Travis Turner <travis@pilosa.com>
522 lines
14 KiB
Go
522 lines
14 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package sql3_test
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/featurebasedb/featurebase/v3/pql"
|
|
)
|
|
|
|
// tableTests is the list of tests which get run by TestSQL_Execute in
|
|
// sql_test.go. They're defined here just to keep the test definitions separate
|
|
// from the test execution logic.
|
|
var tableTests []tableTest = []tableTest{
|
|
{
|
|
name: "minmaxnegatives",
|
|
table: tbl(
|
|
"minmaxnegatives",
|
|
srcHdrs(
|
|
srcHdr("_id", fldTypeID),
|
|
srcHdr("positive_int", fldTypeInt, "min 10", "max 100"),
|
|
srcHdr("negative_int", fldTypeInt, "min -100", "max -10"),
|
|
),
|
|
srcRows(
|
|
srcRow(int64(1), int64(11), int64(-11)),
|
|
srcRow(int64(2), int64(22), int64(-22)),
|
|
srcRow(int64(3), int64(33), int64(-33)),
|
|
),
|
|
),
|
|
sqlTests: []sqlTest{},
|
|
},
|
|
{
|
|
name: "unkeyed",
|
|
table: tbl(
|
|
"unkeyed",
|
|
srcHdrs(
|
|
srcHdr("_id", fldTypeID),
|
|
srcHdr("an_int", fldTypeInt, "min 0", "max 100"),
|
|
srcHdr("an_id_set", fldTypeIDSet),
|
|
srcHdr("an_id", fldTypeID),
|
|
srcHdr("a_string", fldTypeString),
|
|
srcHdr("a_string_set", fldTypeStringSet),
|
|
srcHdr("a_decimal", fldTypeDecimal2),
|
|
),
|
|
srcRows(
|
|
srcRow(int64(1), int64(11), []int64{11, 12, 13}, int64(101), "str1", []string{"a1", "b1", "c1"}, float64(123.45)),
|
|
srcRow(int64(2), int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}, float64(234.56)),
|
|
srcRow(int64(3), int64(33), []int64{31, 32, 33}, int64(301), "str3", []string{"a3", "b3", "c3"}, float64(345.67)),
|
|
srcRow(int64(4), int64(44), []int64{41, 42, 43}, int64(401), "str4", []string{"a4", "b4", "c4"}, float64(456.78)),
|
|
),
|
|
),
|
|
sqlTests: []sqlTest{
|
|
{
|
|
// Select all.
|
|
name: "select-all",
|
|
sqls: sqls(
|
|
"select * from unkeyed",
|
|
"select _id, an_int, an_id_set, an_id, a_string, a_string_set, a_decimal from unkeyed",
|
|
),
|
|
expHdrs: hdrs(
|
|
hdr("_id", fldTypeID),
|
|
hdr("an_int", fldTypeInt),
|
|
hdr("an_id_set", fldTypeIDSet),
|
|
hdr("an_id", fldTypeID),
|
|
hdr("a_string", fldTypeString),
|
|
hdr("a_string_set", fldTypeStringSet),
|
|
hdr("a_decimal", fldTypeDecimal2),
|
|
),
|
|
expRows: rows(
|
|
row(int64(1), int64(11), []int64{11, 12, 13}, int64(101), "str1", []string{"a1", "b1", "c1"}, pql.NewDecimal(12345, 2)),
|
|
row(int64(2), int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}, pql.NewDecimal(23456, 2)),
|
|
row(int64(3), int64(33), []int64{31, 32, 33}, int64(301), "str3", []string{"a3", "b3", "c3"}, pql.NewDecimal(34567, 2)),
|
|
row(int64(4), int64(44), []int64{41, 42, 43}, int64(401), "str4", []string{"a4", "b4", "c4"}, pql.NewDecimal(45678, 2)),
|
|
),
|
|
compare: compareExactUnordered,
|
|
},
|
|
{
|
|
// Select all with top.
|
|
name: "select-all-with-top",
|
|
sqls: sqls(
|
|
"select top(2) * from unkeyed",
|
|
),
|
|
expHdrs: hdrs(
|
|
hdr("_id", fldTypeID),
|
|
hdr("an_int", fldTypeInt),
|
|
hdr("an_id_set", fldTypeIDSet),
|
|
hdr("an_id", fldTypeID),
|
|
hdr("a_string", fldTypeString),
|
|
hdr("a_string_set", fldTypeStringSet),
|
|
hdr("a_decimal", fldTypeDecimal2),
|
|
),
|
|
expRows: rows(
|
|
row(int64(1), int64(11), []int64{11, 12, 13}, int64(101), "str1", []string{"a1", "b1", "c1"}, pql.NewDecimal(12345, 2)),
|
|
row(int64(2), int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}, pql.NewDecimal(23456, 2)),
|
|
),
|
|
compare: compareExactUnordered,
|
|
},
|
|
{
|
|
// Select all with where on each field.
|
|
name: "select-all-with-where",
|
|
sqls: sqls(
|
|
"select * from unkeyed where an_int = 22",
|
|
"select * from unkeyed where a_string = 'str2'",
|
|
"select * from unkeyed where an_id = 201",
|
|
),
|
|
expHdrs: hdrs(
|
|
hdr("_id", fldTypeID),
|
|
hdr("an_int", fldTypeInt),
|
|
hdr("an_id_set", fldTypeIDSet),
|
|
hdr("an_id", fldTypeID),
|
|
hdr("a_string", fldTypeString),
|
|
hdr("a_string_set", fldTypeStringSet),
|
|
hdr("a_decimal", fldTypeDecimal2),
|
|
),
|
|
expRows: rows(
|
|
row(int64(2), int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}, pql.NewDecimal(23456, 2)),
|
|
),
|
|
compare: compareExactOrdered,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
table: tbl(
|
|
"keyed",
|
|
srcHdrs(
|
|
srcHdr("_id", fldTypeString),
|
|
srcHdr("an_int", fldTypeInt, "min 0", "max 100"),
|
|
srcHdr("an_id_set", fldTypeIDSet),
|
|
srcHdr("an_id", fldTypeID),
|
|
srcHdr("a_string", fldTypeString),
|
|
srcHdr("a_string_set", fldTypeStringSet),
|
|
),
|
|
srcRows(
|
|
srcRow("one", int64(11), []int64{11, 12, 13}, int64(101), "str1", []string{"a1", "b1", "c1"}),
|
|
srcRow("two", int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}),
|
|
srcRow("three", int64(33), []int64{31, 32, 33}, int64(301), "str3", []string{"a3", "b3", "c3"}),
|
|
srcRow("four", int64(44), []int64{41, 42, 43}, int64(401), "str4", []string{"a4", "b4", "c4"}),
|
|
),
|
|
),
|
|
sqlTests: []sqlTest{
|
|
{
|
|
// Select all.
|
|
name: "select-all",
|
|
sqls: sqls(
|
|
"select * from keyed",
|
|
"select _id, an_int, an_id_set, an_id, a_string, a_string_set from keyed",
|
|
),
|
|
expHdrs: hdrs(
|
|
hdr("_id", fldTypeString),
|
|
hdr("an_int", fldTypeInt),
|
|
hdr("an_id_set", fldTypeIDSet),
|
|
hdr("an_id", fldTypeID),
|
|
hdr("a_string", fldTypeString),
|
|
hdr("a_string_set", fldTypeStringSet),
|
|
),
|
|
expRows: rows(
|
|
row("one", int64(11), []int64{11, 12, 13}, int64(101), "str1", []string{"a1", "b1", "c1"}),
|
|
row("two", int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}),
|
|
row("three", int64(33), []int64{31, 32, 33}, int64(301), "str3", []string{"a3", "b3", "c3"}),
|
|
row("four", int64(44), []int64{41, 42, 43}, int64(401), "str4", []string{"a4", "b4", "c4"}),
|
|
),
|
|
compare: compareExactUnordered,
|
|
},
|
|
{
|
|
// Select all with top.
|
|
name: "select-all-with-top",
|
|
sqls: sqls(
|
|
"select top(2) * from keyed",
|
|
),
|
|
expHdrs: hdrs(
|
|
hdr("_id", fldTypeString),
|
|
hdr("an_int", fldTypeInt),
|
|
hdr("an_id_set", fldTypeIDSet),
|
|
hdr("an_id", fldTypeID),
|
|
hdr("a_string", fldTypeString),
|
|
hdr("a_string_set", fldTypeStringSet),
|
|
),
|
|
expRows: rows(
|
|
row("one", int64(11), []int64{11, 12, 13}, int64(101), "str1", []string{"a1", "b1", "c1"}),
|
|
row("two", int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}),
|
|
row("three", int64(33), []int64{31, 32, 33}, int64(301), "str3", []string{"a3", "b3", "c3"}),
|
|
row("four", int64(44), []int64{41, 42, 43}, int64(401), "str4", []string{"a4", "b4", "c4"}),
|
|
),
|
|
compare: compareIncludedIn,
|
|
expRowCount: 2,
|
|
},
|
|
{
|
|
// Select all with where on int field.
|
|
name: "select-all-with-where",
|
|
sqls: sqls(
|
|
"select * from keyed where an_int = 22",
|
|
"select * from keyed where a_string = 'str2'",
|
|
"select * from keyed where an_id = 201",
|
|
),
|
|
expHdrs: hdrs(
|
|
hdr("_id", fldTypeString),
|
|
hdr("an_int", fldTypeInt),
|
|
hdr("an_id_set", fldTypeIDSet),
|
|
hdr("an_id", fldTypeID),
|
|
hdr("a_string", fldTypeString),
|
|
hdr("a_string_set", fldTypeStringSet),
|
|
),
|
|
expRows: rows(
|
|
row("two", int64(22), []int64{21, 22, 23}, int64(201), "str2", []string{"a2", "b2", "c2"}),
|
|
),
|
|
compare: compareExactUnordered,
|
|
},
|
|
},
|
|
},
|
|
|
|
setLiteralTests,
|
|
setFunctionTests,
|
|
setParameterTests,
|
|
datePartTests,
|
|
|
|
insertTest,
|
|
keyedInsertTest,
|
|
timestampLiterals,
|
|
unaryOpExprWithInt,
|
|
unaryOpExprWithID,
|
|
unaryOpExprWithBool,
|
|
unaryOpExprWithDecimal,
|
|
unaryOpExprWithTimestamp,
|
|
unaryOpExprWithIDSet,
|
|
unaryOpExprWithString,
|
|
unaryOpExprWithStringSet,
|
|
|
|
binOpExprWithIntInt,
|
|
binOpExprWithIntBool,
|
|
binOpExprWithIntID,
|
|
binOpExprWithIntDecimal,
|
|
binOpExprWithIntTimestamp,
|
|
binOpExprWithIntIDSet,
|
|
binOpExprWithIntString,
|
|
binOpExprWithIntStringSet,
|
|
|
|
binOpExprWithBoolInt,
|
|
binOpExprWithBoolBool,
|
|
binOpExprWithBoolID,
|
|
binOpExprWithBoolDecimal,
|
|
binOpExprWithBoolTimestamp,
|
|
binOpExprWithBoolIDSet,
|
|
binOpExprWithBoolString,
|
|
binOpExprWithBoolStringSet,
|
|
|
|
binOpExprWithIDInt,
|
|
binOpExprWithIDBool,
|
|
binOpExprWithIDID,
|
|
binOpExprWithIDDecimal,
|
|
binOpExprWithIDTimestamp,
|
|
binOpExprWithIDIDSet,
|
|
binOpExprWithIDString,
|
|
binOpExprWithIDStringSet,
|
|
|
|
binOpExprWithDecInt,
|
|
binOpExprWithDecBool,
|
|
binOpExprWithDecID,
|
|
binOpExprWithDecDecimal,
|
|
binOpExprWithDecTimestamp,
|
|
binOpExprWithDecIDSet,
|
|
binOpExprWithDecString,
|
|
binOpExprWithDecStringSet,
|
|
|
|
binOpExprWithTSInt,
|
|
binOpExprWithTSBool,
|
|
binOpExprWithTSID,
|
|
binOpExprWithTSDecimal,
|
|
binOpExprWithTSTimestamp,
|
|
binOpExprWithTSIDSet,
|
|
binOpExprWithTSString,
|
|
binOpExprWithTSStringSet,
|
|
|
|
binOpExprWithIDSetInt,
|
|
binOpExprWithIDSetBool,
|
|
binOpExprWithIDSetID,
|
|
binOpExprWithIDSetDecimal,
|
|
binOpExprWithIDSetTimestamp,
|
|
binOpExprWithIDSetIDSet,
|
|
binOpExprWithIDSetString,
|
|
binOpExprWithIDSetStringSet,
|
|
|
|
binOpExprWithStringInt,
|
|
binOpExprWithStringBool,
|
|
binOpExprWithStringID,
|
|
binOpExprWithStringDecimal,
|
|
binOpExprWithStringTimestamp,
|
|
binOpExprWithStringIDSet,
|
|
binOpExprWithStringString,
|
|
binOpExprWithStringStringSet,
|
|
|
|
binOpExprWithStringSetInt,
|
|
binOpExprWithStringSetBool,
|
|
binOpExprWithStringSetID,
|
|
binOpExprWithStringSetDecimal,
|
|
binOpExprWithStringSetTimestamp,
|
|
binOpExprWithStringSetIDSet,
|
|
binOpExprWithStringSetString,
|
|
binOpExprWithStringSetStringSet,
|
|
|
|
//cast tests
|
|
castIntLiteral,
|
|
castInt,
|
|
|
|
castBool,
|
|
castDecimal,
|
|
castID,
|
|
castIDSet,
|
|
castString,
|
|
castStringSet,
|
|
castTimestamp,
|
|
|
|
//like tests
|
|
likeTests,
|
|
notLikeTests,
|
|
|
|
//null tests
|
|
nullTests,
|
|
notNullTests,
|
|
|
|
//between tests
|
|
betweenTests,
|
|
notBetweenTests,
|
|
|
|
//in tests
|
|
inTests,
|
|
notInTests,
|
|
|
|
//aggregate tests
|
|
countTests,
|
|
countDistinctTests,
|
|
sumTests,
|
|
avgTests,
|
|
percentileTests,
|
|
minmaxTests,
|
|
|
|
//groupby tests
|
|
groupByTests,
|
|
|
|
//create table tests
|
|
createTable,
|
|
|
|
//joins
|
|
joinTestsUsers,
|
|
joinTestsOrders,
|
|
joinTests,
|
|
|
|
//time quantums
|
|
// Skip for now - timeQuantumInsertTest,
|
|
}
|
|
|
|
var insertTest = tableTest{
|
|
table: tbl(
|
|
"testinsert",
|
|
srcHdrs(
|
|
srcHdr("_id", fldTypeID),
|
|
srcHdr("a", fldTypeInt, "min 0", "max 1000"),
|
|
srcHdr("b", fldTypeInt, "min 0", "max 1000"),
|
|
srcHdr("s", fldTypeString),
|
|
srcHdr("bl", fldTypeBool),
|
|
srcHdr("d", fldTypeDecimal2),
|
|
srcHdr("event", fldTypeStringSet),
|
|
srcHdr("ievent", fldTypeIDSet),
|
|
),
|
|
nil,
|
|
),
|
|
sqlTests: []sqlTest{
|
|
{
|
|
// Insert
|
|
sqls: sqls(
|
|
"insert into testinsert (_id, a, b, s, bl, d, event, ievent) values (4, 40, 400, 'foo', false, 10.12, ['A', 'B', 'C'], [1, 2, 3])",
|
|
),
|
|
expHdrs: hdrs(),
|
|
expRows: rows(),
|
|
compare: compareExactUnordered,
|
|
},
|
|
{
|
|
// Insert with nulls
|
|
sqls: sqls(
|
|
"insert into testinsert (_id, a, b, s, bl, d, event, ievent) values (5, null, null, null, null, null, null, null)",
|
|
"insert into testinsert (_id, a, b, s, bl, d, event, ievent) values (6, 1, null, null, null, null, null, null)",
|
|
),
|
|
expHdrs: hdrs(),
|
|
expRows: rows(),
|
|
compare: compareExactUnordered,
|
|
},
|
|
{
|
|
// InsertBadTable
|
|
sqls: sqls(
|
|
"insert into ifoo (a, b) values (1, 2)",
|
|
),
|
|
expErr: "table 'ifoo' not found",
|
|
},
|
|
{
|
|
// InsertBadColumn
|
|
sqls: sqls(
|
|
"insert into testinsert (c, b) values (1, 2)",
|
|
),
|
|
expErr: "column 'c' not found",
|
|
},
|
|
{
|
|
// InsertDupeColumn
|
|
sqls: sqls(
|
|
"insert into testinsert (a, a, b) values (1, 2)",
|
|
),
|
|
expErr: "duplicate column 'a'",
|
|
},
|
|
{
|
|
// InsertMismatchColumnValues
|
|
sqls: sqls(
|
|
"insert into testinsert (_id, a, b) values (1)",
|
|
),
|
|
expErr: "mismatch in the count of expressions and target columns",
|
|
},
|
|
{
|
|
// InsertHandleMissingColumns
|
|
sqls: sqls(
|
|
"insert into testinsert values (4, 40, 400)",
|
|
),
|
|
expErr: "mismatch in the count of expressions and target columns",
|
|
},
|
|
{
|
|
// InsertHandleMissingId
|
|
sqls: sqls(
|
|
"insert into testinsert (a, b) values (1, 2)",
|
|
),
|
|
expErr: "insert column list must have '_id' column specified",
|
|
},
|
|
{
|
|
// InsertHandleMissingIdPlusOneOther
|
|
sqls: sqls(
|
|
"insert into testinsert (_id) values (1)",
|
|
),
|
|
expErr: "insert column list must have at least one non '_id' column specified",
|
|
},
|
|
{
|
|
// InsertSetsTypeError
|
|
sqls: sqls(
|
|
"insert into testinsert (_id, a, event) values (4, 40, [101, 150])",
|
|
),
|
|
expErr: "an expression of type 'IDSET' cannot be assigned to type 'STRINGSET'",
|
|
},
|
|
{
|
|
// InsertSetsTypeError2
|
|
sqls: sqls(
|
|
"insert into testinsert (_id, a, ievent) values (4, 40, ['POST', 'GET'])",
|
|
),
|
|
expErr: "an expression of type 'STRINGSET' cannot be assigned to type 'IDSET'",
|
|
},
|
|
},
|
|
}
|
|
|
|
var keyedInsertTest = tableTest{
|
|
name: "keyedinsert",
|
|
table: tbl(
|
|
"testkeyedinsert",
|
|
srcHdrs(
|
|
srcHdr("_id", fldTypeString),
|
|
srcHdr("a", fldTypeInt, "min 0", "max 1000"),
|
|
srcHdr("b", fldTypeInt, "min 0", "max 1000"),
|
|
srcHdr("s", fldTypeString),
|
|
srcHdr("bl", fldTypeBool),
|
|
srcHdr("d", fldTypeDecimal2),
|
|
srcHdr("event", fldTypeStringSet),
|
|
srcHdr("ievent", fldTypeIDSet),
|
|
),
|
|
nil,
|
|
),
|
|
sqlTests: []sqlTest{
|
|
{
|
|
// Insert
|
|
sqls: sqls(
|
|
"insert into testkeyedinsert (_id, a, b, s, bl, d, event, ievent) values ('four', 40, 400, 'foo', false, 10.12, ['A', 'B', 'C'], [1, 2, 3])",
|
|
),
|
|
expHdrs: hdrs(),
|
|
expRows: rows(),
|
|
compare: compareExactUnordered,
|
|
},
|
|
},
|
|
}
|
|
|
|
func knownTimestamp() time.Time {
|
|
tm, err := time.ParseInLocation(time.RFC3339, "2012-11-01T22:08:41+00:00", time.UTC)
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
return tm
|
|
}
|
|
|
|
var timestampLiterals = tableTest{
|
|
table: tbl(
|
|
"testtimestampliterals",
|
|
srcHdrs(
|
|
srcHdr("_id", fldTypeID),
|
|
srcHdr("a", fldTypeInt, "min 0", "max 1000"),
|
|
srcHdr("b", fldTypeInt, "min 0", "max 1000"),
|
|
srcHdr("d", fldTypeDecimal2),
|
|
srcHdr("ts", fldTypeTimestamp),
|
|
srcHdr("event", fldTypeStringSet),
|
|
srcHdr("ievent", fldTypeIDSet),
|
|
),
|
|
srcRows(),
|
|
),
|
|
sqlTests: []sqlTest{
|
|
{
|
|
// InsertWithCurrentTimestamp
|
|
sqls: sqls(
|
|
"insert into testtimestampliterals (_id, a, b, d, ts, event, ievent) values (4, 40, 400, 10.12, current_timestamp, ['A', 'B', 'C'], [1, 2, 3])",
|
|
),
|
|
expHdrs: hdrs(),
|
|
expRows: rows(),
|
|
compare: compareExactUnordered,
|
|
},
|
|
{
|
|
// InsertWithCurrentDate
|
|
sqls: sqls(
|
|
"insert into testtimestampliterals (_id, a, b, d, ts, event, ievent) values (4, 40, 400, 10.12, current_date, ['A', 'B', 'C'], [1, 2, 3])",
|
|
),
|
|
expHdrs: hdrs(),
|
|
expRows: rows(),
|
|
compare: compareExactUnordered,
|
|
},
|
|
},
|
|
}
|