mirror of
https://github.com/chaisql/chai.git
synced 2025-09-26 19:51:21 +08:00
remove rowid
This commit is contained in:
@@ -53,7 +53,7 @@ func TestDump(t *testing.T) {
|
||||
writeToBuf("\n")
|
||||
}
|
||||
|
||||
q := fmt.Sprintf("CREATE TABLE %s (a INTEGER, b INTEGER, c INTEGER);", table)
|
||||
q := fmt.Sprintf("CREATE TABLE %s (a INTEGER NOT NULL, b INTEGER, c INTEGER, CONSTRAINT %s_pk PRIMARY KEY (a));", table, table)
|
||||
_, err = db.Exec(q)
|
||||
require.NoError(t, err)
|
||||
writeToBuf(q + "\n")
|
||||
|
@@ -17,7 +17,7 @@ func TestExecSQL(t *testing.T) {
|
||||
|
||||
var got bytes.Buffer
|
||||
err = ExecSQL(t.Context(), db, strings.NewReader(`
|
||||
CREATE TABLE test(a INT, b TEXT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY, b TEXT);
|
||||
CREATE INDEX idx_a ON test (a);
|
||||
BEGIN;
|
||||
INSERT INTO test (a, b) VALUES (10, 'aa'), (20, 'bb'), (30, 'cc');
|
||||
|
@@ -39,7 +39,7 @@ func TestRunTablesCmd(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
for _, tb := range test.tables {
|
||||
_, err := db.Exec("CREATE TABLE " + tb + "(a INT)")
|
||||
_, err := db.Exec("CREATE TABLE " + tb + "(a INT PRIMARY KEY)")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -71,10 +71,10 @@ func TestIndexesCmd(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE foo(a INT, b INT);
|
||||
CREATE TABLE foo(a INT PRIMARY KEY, b INT);
|
||||
CREATE INDEX idx_foo_a ON foo (a);
|
||||
CREATE INDEX idx_foo_b ON foo (b);
|
||||
CREATE TABLE bar(a INT, b INT);
|
||||
CREATE TABLE bar(a INT PRIMARY KEY, b INT);
|
||||
CREATE INDEX idx_bar_a_b ON bar (a, b);
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
@@ -102,7 +102,7 @@ func TestSaveCommand(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE test (a DOUBLE, b INT);
|
||||
CREATE TABLE test (a DOUBLE PRIMARY KEY, b INT);
|
||||
CREATE INDEX idx_a_b ON test (a, b);
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
106
db_test.go
106
db_test.go
@@ -66,7 +66,7 @@ func TestOpen(t *testing.T) {
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE tableA (a INTEGER UNIQUE NOT NULL, b DOUBLE PRIMARY KEY);
|
||||
CREATE TABLE tableB (a TEXT NOT NULL DEFAULT 'hello', PRIMARY KEY (a));
|
||||
CREATE TABLE tableC (a INTEGER, b INTEGER);
|
||||
CREATE TABLE tableC (a INTEGER PRIMARY KEY, b INTEGER);
|
||||
CREATE INDEX tableC_a_b_idx ON tableC(a, b);
|
||||
CREATE SEQUENCE seqD INCREMENT BY 10 CYCLE MINVALUE 100 NO MAXVALUE START 500;
|
||||
|
||||
@@ -98,9 +98,8 @@ func TestOpen(t *testing.T) {
|
||||
`{"name":"tableA", "namespace":10, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE TABLE tableA (a INTEGER NOT NULL, b DOUBLE NOT NULL, CONSTRAINT tableA_a_unique UNIQUE (a), CONSTRAINT tableA_pk PRIMARY KEY (b))", "type":"table"}`,
|
||||
`{"name":"tableA_a_idx", "namespace":11, "owner_table_columns":"a", "owner_table_name":"tableA", "rowid_sequence_name":null, "sql":"CREATE UNIQUE INDEX tableA_a_idx ON tableA (a)", "type":"index"}`,
|
||||
`{"name":"tableB", "namespace":12, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE TABLE tableB (a TEXT NOT NULL DEFAULT \"hello\", CONSTRAINT tableB_pk PRIMARY KEY (a))", "type":"table"}`,
|
||||
`{"name":"tableC", "namespace":13, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":"tableC_seq", "sql":"CREATE TABLE tableC (a INTEGER, b INTEGER)", "type":"table"}`,
|
||||
`{"name":"tableC", "namespace":13, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE TABLE tableC (a INTEGER NOT NULL, b INTEGER, CONSTRAINT tableC_pk PRIMARY KEY (a))", "type":"table"}`,
|
||||
`{"name":"tableC_a_b_idx", "namespace":14, "owner_table_columns":null, "owner_table_name":"tableC", "rowid_sequence_name":null, "sql":"CREATE INDEX tableC_a_b_idx ON tableC (a, b)", "type":"index"}`,
|
||||
`{"name":"tableC_seq", "namespace":null, "owner_table_columns":null, "owner_table_name":"tableC", "rowid_sequence_name":null, "sql":"CREATE SEQUENCE tableC_seq CACHE 64", "type":"sequence"}`,
|
||||
}
|
||||
testutil.RequireJSONEq(t, rows, want...)
|
||||
|
||||
@@ -279,3 +278,104 @@ func TestRWConcurrency(t *testing.T) {
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestOrderByConcurrency(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
db, err := sql.Open("chai", dir)
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
tx, err := db.Begin()
|
||||
require.NoError(t, err)
|
||||
_, err = tx.Exec(`
|
||||
CREATE TABLE foo (
|
||||
a integer primary key,
|
||||
b int not null
|
||||
);`)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := range 10_000 {
|
||||
_, err := tx.Exec(`INSERT INTO foo (a, b) VALUES ($1, $2)`, i, i)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NoError(t, tx.Commit())
|
||||
|
||||
iterations := 10
|
||||
concurrency := 8
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(concurrency)
|
||||
|
||||
for i := range concurrency {
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
for j := 0; j < iterations; j++ {
|
||||
var desc string
|
||||
if j%2 == 0 {
|
||||
desc = "DESC"
|
||||
} else {
|
||||
desc = "ASC"
|
||||
}
|
||||
func() {
|
||||
rows, err := db.Query(`SELECT * FROM foo ORDER BY b ` + desc)
|
||||
require.NoError(t, err)
|
||||
defer rows.Close()
|
||||
|
||||
var count int
|
||||
for rows.Next() {
|
||||
var a int
|
||||
var b int
|
||||
err := rows.Scan(&a, &b)
|
||||
require.NoError(t, err)
|
||||
if desc == "ASC" {
|
||||
require.Equal(t, count, a)
|
||||
require.Equal(t, count, b)
|
||||
} else {
|
||||
require.Equal(t, 9_999-count, a)
|
||||
require.Equal(t, 9_999-count, b)
|
||||
}
|
||||
count++
|
||||
}
|
||||
require.NoError(t, rows.Err())
|
||||
require.Equal(t, 10_000, count)
|
||||
}()
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkOrderBy(b *testing.B) {
|
||||
dir := b.TempDir()
|
||||
db, err := sql.Open("chai", dir)
|
||||
require.NoError(b, err)
|
||||
defer db.Close()
|
||||
|
||||
tx, err := db.Begin()
|
||||
require.NoError(b, err)
|
||||
_, err = tx.Exec(`
|
||||
CREATE TABLE foo (
|
||||
a integer primary key,
|
||||
b int not null
|
||||
);`)
|
||||
require.NoError(b, err)
|
||||
|
||||
for i := range 10_000 {
|
||||
_, err := tx.Exec(`INSERT INTO foo (a, b) VALUES ($1, $2)`, i, i)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
require.NoError(b, tx.Commit())
|
||||
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
rows, err := db.Query(`SELECT * FROM foo ORDER BY b`)
|
||||
require.NoError(b, err)
|
||||
|
||||
for rows.Next() {
|
||||
var a int
|
||||
var b int
|
||||
_ = rows.Scan(&a, &b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ func Example() {
|
||||
defer db.Close()
|
||||
|
||||
// Create a table.
|
||||
_, err = db.Exec("CREATE TABLE user (id int, name text, age int)")
|
||||
_, err = db.Exec("CREATE TABLE user (id int primary key, name text, age int)")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
11
go.work.sum
11
go.work.sum
@@ -171,10 +171,6 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/RaduBerinde/axisds v0.0.0-20250419182453-5135a0650657 h1:8XBWWQD+vFF+JqOsm16t0Kab1a7YWV8+GISVEP8AuZ8=
|
||||
github.com/RaduBerinde/axisds v0.0.0-20250419182453-5135a0650657/go.mod h1:UHGJonU9z4YYGKJxSaC6/TNcLOBptpmM5m2Cksbnw0Y=
|
||||
github.com/RaduBerinde/btreemap v0.0.0-20250419174037-3d62b7205d54 h1:bsU8Tzxr/PNz75ayvCnxKZWEYdLMPDkUgticP4a4Bvk=
|
||||
github.com/RaduBerinde/btreemap v0.0.0-20250419174037-3d62b7205d54/go.mod h1:0tr7FllbE9gJkHq7CVeeDDFAFKQVy5RnCSSNBOvdqbc=
|
||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
|
||||
github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes=
|
||||
github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794/go.mod h1:7e+I0LQFUI9AXWxOfsQROs9xPhoJtbsyWcjJqDd4KPY=
|
||||
@@ -224,12 +220,9 @@ github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cockroachdb/crlib v0.0.0-20241015224233-894974b3ad94/go.mod h1:Gq51ZeKaFCXk6QwuGM0w1dnaOqc/F5zKT2zA9D6Xeac=
|
||||
github.com/cockroachdb/crlib v0.0.0-20241112164430-1264a2edc35b/go.mod h1:Gq51ZeKaFCXk6QwuGM0w1dnaOqc/F5zKT2zA9D6Xeac=
|
||||
github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
|
||||
github.com/cockroachdb/datadriven v1.0.3-0.20250407164829-2945557346d5/go.mod h1:jsaKMvD3RBCATk1/jbUZM8C9idWBJME9+VRZ5+Liq1g=
|
||||
github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
|
||||
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||
github.com/cockroachdb/pebble/v2 v2.1.0 h1:6KZvjSpWcEXZUvlLzTRC7T1A2G7r+bFskIzggklxixo=
|
||||
github.com/cockroachdb/pebble/v2 v2.1.0/go.mod h1:Aza05DCCc05ghIJZkB4Q/axv/JK9wx5cFwWcnhG0eGw=
|
||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
@@ -452,14 +445,14 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
|
||||
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4=
|
||||
github.com/minio/minlz v1.0.1-0.20250507153514-87eb42fe8882 h1:0lgqHvJWHLGW5TuObJrfyEi6+ASTKDBWikGvPqy9Yiw=
|
||||
github.com/minio/minlz v1.0.1-0.20250507153514-87eb42fe8882/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
|
@@ -902,9 +902,6 @@ func tableInfoToRow(ti *TableInfo) row.Row {
|
||||
buf.Add("type", types.NewTextValue(RelationTableType))
|
||||
buf.Add("namespace", types.NewBigintValue(int64(ti.StoreNamespace)))
|
||||
buf.Add("sql", types.NewTextValue(ti.String()))
|
||||
if ti.RowidSequenceName != "" {
|
||||
buf.Add("rowid_sequence_name", types.NewTextValue(ti.RowidSequenceName))
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
@@ -449,7 +449,7 @@ func TestReadOnlyTables(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query(`
|
||||
CREATE TABLE foo (a int, b double unique, c text);
|
||||
CREATE TABLE foo (a int primary key, b double unique, c text);
|
||||
CREATE INDEX idx_foo_a ON foo(a, c);
|
||||
SELECT * FROM __chai_catalog
|
||||
`)
|
||||
@@ -460,9 +460,8 @@ func TestReadOnlyTables(t *testing.T) {
|
||||
`{"name":"__chai_catalog", "namespace":1, "owner_table_name": null, "owner_table_columns": null, "rowid_sequence_name": null, "sql":"CREATE TABLE __chai_catalog (name TEXT NOT NULL, type TEXT NOT NULL, namespace BIGINT, sql TEXT, rowid_sequence_name TEXT, owner_table_name TEXT, owner_table_columns TEXT, CONSTRAINT __chai_catalog_pk PRIMARY KEY (name))", "type":"table"}`,
|
||||
`{"name":"__chai_sequence", "namespace":2, "owner_table_name": null, "owner_table_columns":null, "rowid_sequence_name": null, "sql":"CREATE TABLE __chai_sequence (name TEXT NOT NULL, seq BIGINT, CONSTRAINT __chai_sequence_pk PRIMARY KEY (name))", "type":"table"}`,
|
||||
`{"name":"__chai_store_seq", "namespace":null, "owner_table_name": "__chai_catalog", "owner_table_columns":null, "rowid_sequence_name": null, "sql":"CREATE SEQUENCE __chai_store_seq MAXVALUE 9223372036837998591 START WITH 10", "type":"sequence"}`,
|
||||
`{"name":"foo", "namespace":10, "owner_table_name": null, "owner_table_columns":null, "rowid_sequence_name":"foo_seq", "sql":"CREATE TABLE foo (a INTEGER, b DOUBLE, c TEXT, CONSTRAINT foo_b_unique UNIQUE (b))", "namespace":10, "type":"table"}`,
|
||||
`{"name":"foo", "namespace":10, "owner_table_name": null, "owner_table_columns":null, "rowid_sequence_name":null, "sql":"CREATE TABLE foo (a INTEGER NOT NULL, b DOUBLE, c TEXT, CONSTRAINT foo_pk PRIMARY KEY (a), CONSTRAINT foo_b_unique UNIQUE (b))", "namespace":10, "type":"table"}`,
|
||||
`{"name":"foo_b_idx", "namespace":11, "owner_table_name":"foo", "owner_table_columns": "b", "rowid_sequence_name": null, "sql":"CREATE UNIQUE INDEX foo_b_idx ON foo (b)", "type":"index"}`,
|
||||
`{"name":"foo_seq", "namespace":null, "owner_table_name":"foo", "owner_table_columns":null, "rowid_sequence_name": null, "sql":"CREATE SEQUENCE foo_seq CACHE 64", "type":"sequence"}`,
|
||||
`{"name":"idx_foo_a", "namespace":12, "owner_table_name":"foo", "owner_table_columns":null, "rowid_sequence_name": null, "sql":"CREATE INDEX idx_foo_a ON foo (a, c)", "type":"index", "owner_table_name":"foo"}`,
|
||||
)
|
||||
}
|
||||
@@ -558,7 +557,7 @@ func TestCatalogConcurrency(t *testing.T) {
|
||||
|
||||
// create a table
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE test (a int);
|
||||
CREATE TABLE test (a int primary key);
|
||||
CREATE INDEX idx_test_a ON test(a);
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
@@ -575,7 +574,7 @@ func TestCatalogConcurrency(t *testing.T) {
|
||||
|
||||
// update the catalog in wt2
|
||||
_, err = wt1.Exec(`
|
||||
CREATE TABLE test2 (a int);
|
||||
CREATE TABLE test2 (a int primary key);
|
||||
CREATE INDEX idx_test2_a ON test2(a);
|
||||
ALTER TABLE test ADD COLUMN b int;
|
||||
`)
|
||||
@@ -591,7 +590,7 @@ func TestCatalogConcurrency(t *testing.T) {
|
||||
var s string
|
||||
err = rt1.QueryRow("SELECT sql FROM __chai_catalog WHERE name = 'test'").Scan(&s)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "CREATE TABLE test (a INTEGER)", s)
|
||||
require.Equal(t, "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a))", s)
|
||||
|
||||
// commit wt2
|
||||
err = wt1.Commit()
|
||||
@@ -605,5 +604,5 @@ func TestCatalogConcurrency(t *testing.T) {
|
||||
// get the modified table in rt1: should not see the changes made by wt2
|
||||
err = rt1.QueryRow("SELECT sql FROM __chai_catalog WHERE name = 'test'").Scan(&s)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "CREATE TABLE test (a INTEGER)", s)
|
||||
require.Equal(t, "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a))", s)
|
||||
}
|
||||
|
@@ -154,14 +154,6 @@ func tableInfoFromRow(r database.Row) (*database.TableInfo, error) {
|
||||
|
||||
ti.StoreNamespace = tree.Namespace(storeNamespace)
|
||||
|
||||
v, err = r.Get("rowid_sequence_name")
|
||||
if err != nil && !errors.Is(err, types.ErrColumnNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
if err == nil && v.Type() != types.TypeNull {
|
||||
ti.RowidSequenceName = types.AsString(v)
|
||||
}
|
||||
|
||||
ti.BuildPrimaryKey()
|
||||
|
||||
return &ti, nil
|
||||
|
@@ -118,7 +118,7 @@ type TableExpression interface {
|
||||
}
|
||||
|
||||
// A TableConstraint represent a constraint specific to a table
|
||||
// and not necessarily to a single field path.
|
||||
// and not necessarily to a single column.
|
||||
type TableConstraint struct {
|
||||
Name string
|
||||
Columns []string
|
||||
|
@@ -21,9 +21,6 @@ type TableInfo struct {
|
||||
StoreNamespace tree.Namespace
|
||||
ReadOnly bool
|
||||
|
||||
// Name of the rowid sequence if any.
|
||||
RowidSequenceName string
|
||||
|
||||
ColumnConstraints ColumnConstraints
|
||||
TableConstraints TableConstraints
|
||||
|
||||
|
@@ -36,7 +36,7 @@ func (t *Table) Insert(r row.Row) (*tree.Key, Row, error) {
|
||||
return nil, nil, errors.New("cannot write to read-only table")
|
||||
}
|
||||
|
||||
key, isRowid, err := t.GenerateKey(r)
|
||||
key, err := t.GenerateKey(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -47,13 +47,7 @@ func (t *Table) Insert(r row.Row) (*tree.Key, Row, error) {
|
||||
}
|
||||
|
||||
// insert into the table
|
||||
if !isRowid {
|
||||
// if the key is not a rowid, make sure it doesn't exist
|
||||
// by using Insert instead of Put
|
||||
err = t.Tree.Insert(key, enc)
|
||||
} else {
|
||||
err = t.Tree.Put(key, enc)
|
||||
}
|
||||
err = t.Tree.Insert(key, enc)
|
||||
if err != nil {
|
||||
if errors.Is(err, engine.ErrKeyAlreadyExists) {
|
||||
return nil, nil, &ConstraintViolationError{
|
||||
@@ -195,38 +189,21 @@ func (t *Table) GetRow(key *tree.Key) (Row, error) {
|
||||
}
|
||||
|
||||
// GenerateKey generates a key for o based on the table configuration.
|
||||
// if the table has a primary key, it extracts the field from
|
||||
// the object, converts it to the targeted type and returns
|
||||
// its encoded version.
|
||||
// if there are no primary key in the table, a default
|
||||
// key is generated, called the rowid.
|
||||
// It returns a boolean indicating whether the key is a rowid or not.
|
||||
func (t *Table) GenerateKey(r row.Row) (*tree.Key, bool, error) {
|
||||
if pk := t.Info.PrimaryKey; pk != nil {
|
||||
vs := make([]types.Value, 0, len(pk.Columns))
|
||||
for _, c := range pk.Columns {
|
||||
v, err := r.Get(c)
|
||||
if errors.Is(err, types.ErrColumnNotFound) {
|
||||
return nil, false, fmt.Errorf("missing primary key at path %q", c)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
vs = append(vs, v)
|
||||
func (t *Table) GenerateKey(r row.Row) (*tree.Key, error) {
|
||||
pk := t.Info.PrimaryKey
|
||||
vs := make([]types.Value, 0, len(pk.Columns))
|
||||
for _, c := range pk.Columns {
|
||||
v, err := r.Get(c)
|
||||
if errors.Is(err, types.ErrColumnNotFound) {
|
||||
return nil, fmt.Errorf("missing primary key at path %q", c)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tree.NewKey(vs...), false, nil
|
||||
vs = append(vs, v)
|
||||
}
|
||||
|
||||
seq, err := t.Tx.Catalog.GetSequence(t.Info.RowidSequenceName)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
rowid, err := seq.Next(t.Tx)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
|
||||
return tree.NewKey(types.NewBigintValue(rowid)), true, nil
|
||||
return tree.NewKey(vs...), nil
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/chaisql/chai/internal/database"
|
||||
"github.com/chaisql/chai/internal/database/catalogstore"
|
||||
errs "github.com/chaisql/chai/internal/errors"
|
||||
"github.com/chaisql/chai/internal/query/statement"
|
||||
"github.com/chaisql/chai/internal/row"
|
||||
@@ -49,6 +48,10 @@ func newTestTable(t testing.TB) (*database.Table, func()) {
|
||||
|
||||
ti := database.TableInfo{
|
||||
TableName: "test",
|
||||
PrimaryKey: &database.PrimaryKey{
|
||||
Columns: []string{"a"},
|
||||
Types: []types.Type{types.TypeText},
|
||||
},
|
||||
ColumnConstraints: database.MustNewColumnConstraints(
|
||||
&database.ColumnConstraint{
|
||||
Position: 0,
|
||||
@@ -61,11 +64,19 @@ func newTestTable(t testing.TB) (*database.Table, func()) {
|
||||
Type: types.TypeText,
|
||||
},
|
||||
),
|
||||
TableConstraints: database.TableConstraints{
|
||||
&database.TableConstraint{
|
||||
PrimaryKey: true,
|
||||
Columns: []string{"a"},
|
||||
},
|
||||
},
|
||||
}
|
||||
return createTable(t, tx, ti), fn
|
||||
}
|
||||
|
||||
func createTable(t testing.TB, tx *database.Transaction, info database.TableInfo) *database.Table {
|
||||
t.Helper()
|
||||
|
||||
stmt := statement.CreateTableStmt{Info: info}
|
||||
|
||||
res, err := stmt.Run(&statement.Context{
|
||||
@@ -138,76 +149,6 @@ func TestTableGetRow(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestTableInsert verifies Insert behaviour.
|
||||
func TestTableInsert(t *testing.T) {
|
||||
t.Run("Should generate the right rowid on existing databases", func(t *testing.T) {
|
||||
path := t.TempDir()
|
||||
db1, err := database.Open(path, &database.Options{
|
||||
CatalogLoader: catalogstore.LoadCatalog,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
insertRow := func(db *database.Database) (rawKey *tree.Key) {
|
||||
t.Helper()
|
||||
|
||||
update(t, db, func(tx *database.Transaction) error {
|
||||
t.Helper()
|
||||
|
||||
// create table if not exists
|
||||
ti := database.TableInfo{
|
||||
TableName: "test",
|
||||
ColumnConstraints: database.MustNewColumnConstraints(
|
||||
&database.ColumnConstraint{
|
||||
Position: 0,
|
||||
Column: "a",
|
||||
Type: types.TypeText,
|
||||
},
|
||||
&database.ColumnConstraint{
|
||||
Position: 0,
|
||||
Column: "b",
|
||||
Type: types.TypeText,
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
tb := createTableIfNotExists(t, tx, ti)
|
||||
|
||||
r := newRow()
|
||||
key, _, err := tb.Insert(r)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, key)
|
||||
rawKey = key
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
key1 := insertRow(db1)
|
||||
|
||||
err = db1.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
// create a new database object
|
||||
db2, err := database.Open(path, &database.Options{
|
||||
CatalogLoader: catalogstore.LoadCatalog,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
key2 := insertRow(db2)
|
||||
|
||||
vs, err := key1.Decode()
|
||||
require.NoError(t, err)
|
||||
a := vs[0].V().(int64)
|
||||
|
||||
vs, err = key2.Decode()
|
||||
require.NoError(t, err)
|
||||
b := vs[0].V().(int64)
|
||||
|
||||
require.Equal(t, int64(a+1), int64(b))
|
||||
db2.Close()
|
||||
})
|
||||
}
|
||||
|
||||
// TestTableDelete verifies Delete behaviour.
|
||||
func TestTableDelete(t *testing.T) {
|
||||
t.Run("Should not fail if not found", func(t *testing.T) {
|
||||
@@ -216,35 +157,6 @@ func TestTableDelete(t *testing.T) {
|
||||
err := tb.Delete(tree.NewKey(types.NewIntegerValue(10)))
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Should delete the right object", func(t *testing.T) {
|
||||
tb, cleanup := newTestTable(t)
|
||||
defer cleanup()
|
||||
|
||||
// create two objects, one with an additional field
|
||||
row1 := newRow()
|
||||
row1.Add("fieldc", types.NewIntegerValue(40))
|
||||
row2 := newRow()
|
||||
|
||||
key1, _, err := tb.Insert(testutil.CloneRow(t, row1))
|
||||
require.NoError(t, err)
|
||||
key2, _, err := tb.Insert(testutil.CloneRow(t, row2))
|
||||
require.NoError(t, err)
|
||||
|
||||
// delete the object
|
||||
err = tb.Delete(key1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// try again, should fail
|
||||
_, err = tb.GetRow(key1)
|
||||
require.True(t, errs.IsNotFoundError(err))
|
||||
|
||||
// make sure it didn't also delete the other one
|
||||
res, err := tb.GetRow(key2)
|
||||
require.NoError(t, err)
|
||||
_, err = res.Get("fieldc")
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// TestTableReplace verifies Replace behaviour.
|
||||
@@ -308,30 +220,6 @@ func TestTableTruncate(t *testing.T) {
|
||||
err := tb.Truncate()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Should truncate the table", func(t *testing.T) {
|
||||
tb, cleanup := newTestTable(t)
|
||||
defer cleanup()
|
||||
|
||||
// create two objects
|
||||
row1 := newRow()
|
||||
row2 := newRow()
|
||||
|
||||
_, _, err := tb.Insert(row1)
|
||||
require.NoError(t, err)
|
||||
_, _, err = tb.Insert(row2)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = tb.Truncate()
|
||||
require.NoError(t, err)
|
||||
|
||||
it, err := tb.Iterator(nil)
|
||||
require.NoError(t, err)
|
||||
defer it.Close()
|
||||
|
||||
it.First()
|
||||
require.False(t, it.Valid())
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkTableInsert benchmarks the Insert method with 1, 10, 1000 and 10000 successive insertions.
|
||||
|
@@ -252,7 +252,7 @@ func TestQueries(t *testing.T) {
|
||||
|
||||
var count int
|
||||
err = db.QueryRow(`
|
||||
CREATE TABLE test(a INT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4);
|
||||
SELECT COUNT(*) FROM test;
|
||||
`).Scan(&count)
|
||||
@@ -282,7 +282,7 @@ func TestQueries(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE test(a INT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4);
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
@@ -295,10 +295,10 @@ func TestQueries(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
rows, err := db.Query(`
|
||||
CREATE TABLE test(a INT);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT);
|
||||
INSERT INTO test (pk, a) VALUES (1, 1), (2, 2), (3, 3), (4, 4);
|
||||
UPDATE test SET a = 5;
|
||||
SELECT * FROM test;
|
||||
SELECT a FROM test;
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -311,7 +311,7 @@ func TestQueries(t *testing.T) {
|
||||
db, err := sql.Open("chai", filepath.Join(dir, "pebble"))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec("CREATE TABLE test(a INT)")
|
||||
_, err = db.Exec("CREATE TABLE test(a INT PRIMARY KEY);")
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, err := db.Begin()
|
||||
@@ -350,7 +350,7 @@ func TestQueriesSameTransaction(t *testing.T) {
|
||||
|
||||
var count int
|
||||
err = tx.QueryRow(`
|
||||
CREATE TABLE test(a INT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4);
|
||||
SELECT COUNT(*) FROM test;
|
||||
`).Scan(&count)
|
||||
@@ -372,7 +372,7 @@ func TestQueriesSameTransaction(t *testing.T) {
|
||||
defer tx.Rollback()
|
||||
|
||||
_, err = tx.Exec(`
|
||||
CREATE TABLE test(a INT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4);
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
@@ -392,10 +392,10 @@ func TestQueriesSameTransaction(t *testing.T) {
|
||||
defer tx.Rollback()
|
||||
|
||||
rows, err := tx.Query(`
|
||||
CREATE TABLE test(a INT);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT);
|
||||
INSERT INTO test (pk, a) VALUES (1, 1), (2, 2), (3, 3), (4, 4);
|
||||
UPDATE test SET a = 5;
|
||||
SELECT * FROM test;
|
||||
SELECT a FROM test;
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -417,7 +417,7 @@ func TestQueriesSameTransaction(t *testing.T) {
|
||||
|
||||
var count int
|
||||
err = tx.QueryRow(`
|
||||
CREATE TABLE test(a INT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
|
||||
DELETE FROM test WHERE a > 2;
|
||||
SELECT COUNT(*) FROM test;
|
||||
|
@@ -607,8 +607,8 @@ func TestOptimize(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
testutil.MustExec(t, db, tx, `
|
||||
CREATE TABLE foo(a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE bar(a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE foo(pk INT PRIMARY KEY, a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE bar(pk INT PRIMARY KEY, a INT, b INT, c INT, d INT);
|
||||
`)
|
||||
|
||||
got, err := planner.Optimize(
|
||||
@@ -642,8 +642,8 @@ func TestOptimize(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
testutil.MustExec(t, db, tx, `
|
||||
CREATE TABLE foo(a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE bar(a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE foo(pk INT PRIMARY KEY, a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE bar(pk INT PRIMARY KEY, a INT, b INT, c INT, d INT);
|
||||
`)
|
||||
|
||||
got, err := planner.Optimize(
|
||||
@@ -675,8 +675,8 @@ func TestOptimize(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
testutil.MustExec(t, db, tx, `
|
||||
CREATE TABLE foo(a INT, d INT);
|
||||
CREATE TABLE bar(a INT, d INT);
|
||||
CREATE TABLE foo(a INT PRIMARY KEY, d INT);
|
||||
CREATE TABLE bar(a INT PRIMARY KEY, d INT);
|
||||
CREATE INDEX idx_foo_a_d ON foo(a, d);
|
||||
CREATE INDEX idx_bar_a_d ON bar(a, d);
|
||||
`)
|
||||
|
@@ -14,7 +14,7 @@ func TestAlterTable(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE foo(name TEXT, age INT)")
|
||||
_, err = db.Exec("CREATE TABLE foo(name TEXT PRIMARY KEY, age INT)")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Insert some data into foo
|
||||
|
@@ -1,14 +1,13 @@
|
||||
package statement
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/chaisql/chai/internal/database"
|
||||
errs "github.com/chaisql/chai/internal/errors"
|
||||
"github.com/chaisql/chai/internal/planner"
|
||||
"github.com/chaisql/chai/internal/stream"
|
||||
"github.com/chaisql/chai/internal/stream/index"
|
||||
"github.com/chaisql/chai/internal/stream/table"
|
||||
"github.com/cockroachdb/errors"
|
||||
)
|
||||
|
||||
var _ Statement = (*CreateTableStmt)(nil)
|
||||
@@ -24,23 +23,17 @@ type CreateTableStmt struct {
|
||||
// Run runs the Create table statement in the given transaction.
|
||||
// It implements the Statement interface.
|
||||
func (stmt *CreateTableStmt) Run(ctx *Context) (*Result, error) {
|
||||
// if there is no primary key, create a rowid sequence
|
||||
if stmt.Info.PrimaryKey == nil {
|
||||
seq := database.SequenceInfo{
|
||||
IncrementBy: 1,
|
||||
Min: 1, Max: math.MaxInt64,
|
||||
Start: 1,
|
||||
Cache: 64,
|
||||
Owner: database.Owner{
|
||||
TableName: stmt.Info.TableName,
|
||||
},
|
||||
}
|
||||
err := ctx.Conn.GetTx().CatalogWriter().CreateSequence(ctx.Conn.GetTx(), &seq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errors.New("table must have a primary key")
|
||||
}
|
||||
|
||||
stmt.Info.RowidSequenceName = seq.Name
|
||||
// for each primary key column, add a not null constraint
|
||||
for _, col := range stmt.Info.PrimaryKey.Columns {
|
||||
cc := stmt.Info.GetColumnConstraint(col)
|
||||
if cc == nil {
|
||||
return nil, errors.Errorf("primary key column %q does not exist", col)
|
||||
}
|
||||
cc.IsNotNull = true
|
||||
}
|
||||
|
||||
err := ctx.Conn.GetTx().CatalogWriter().CreateTable(ctx.Conn.GetTx(), stmt.Info.TableName, &stmt.Info)
|
||||
|
@@ -29,7 +29,7 @@ func TestCreateIndex(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(foo TEXT, baz INT, baf BOOL)")
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(pk INT PRIMARY KEY, foo TEXT, baz INT, baf BOOL)")
|
||||
|
||||
err := testutil.Exec(db, tx, test.query)
|
||||
if test.fails {
|
||||
|
@@ -33,7 +33,7 @@ func (stmt *DropTableStmt) Run(ctx *Context) (*Result, error) {
|
||||
return nil, errors.New("missing table name")
|
||||
}
|
||||
|
||||
tb, err := ctx.Conn.GetTx().Catalog.GetTable(ctx.Conn.GetTx(), stmt.TableName)
|
||||
_, err := ctx.Conn.GetTx().Catalog.GetTable(ctx.Conn.GetTx(), stmt.TableName)
|
||||
if err != nil {
|
||||
if errs.IsNotFoundError(err) && stmt.IfExists {
|
||||
err = nil
|
||||
@@ -47,14 +47,6 @@ func (stmt *DropTableStmt) Run(ctx *Context) (*Result, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if there is no primary key, drop the rowid sequence
|
||||
if tb.Info.PrimaryKey == nil {
|
||||
err = ctx.Conn.GetTx().CatalogWriter().DropSequence(ctx.Conn.GetTx(), tb.Info.RowidSequenceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,7 @@ func TestDropTable(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE test1(a INT UNIQUE); CREATE TABLE test2(a INT); CREATE TABLE test3(a INT)")
|
||||
_, err = db.Exec("CREATE TABLE test1(pk INT PRIMARY KEY, a INT UNIQUE); CREATE TABLE test2(pk INT PRIMARY KEY, a INT); CREATE TABLE test3(pk INT PRIMARY KEY, a INT)")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec("DROP TABLE test1")
|
||||
@@ -66,8 +66,8 @@ func TestDropIndex(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, `
|
||||
CREATE TABLE test1(foo text, bar int unique); CREATE INDEX idx_test1_foo ON test1(foo);
|
||||
CREATE TABLE test2(bar text); CREATE INDEX idx_test2_bar ON test2(bar);
|
||||
CREATE TABLE test1(pk int primary key, foo text, bar int unique); CREATE INDEX idx_test1_foo ON test1(foo);
|
||||
CREATE TABLE test2(pk int primary key, bar text); CREATE INDEX idx_test2_bar ON test2(bar);
|
||||
`)
|
||||
|
||||
testutil.MustExec(t, db, tx, "DROP INDEX idx_test2_bar")
|
||||
@@ -92,7 +92,7 @@ func TestDropSequence(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, `
|
||||
CREATE TABLE test1(foo int);
|
||||
CREATE TABLE test1(foo int primary key, bar int unique);
|
||||
CREATE SEQUENCE seq1;
|
||||
CREATE SEQUENCE seq2;
|
||||
`)
|
||||
|
@@ -16,8 +16,8 @@ func TestInsertStmt(t *testing.T) {
|
||||
expected string
|
||||
params []any
|
||||
}{
|
||||
{"Values / Positional Params", "INSERT INTO test (a, b, c) VALUES ($1, 'e', $2)", false, `[{"a":"d","b":"e","c":"f"}]`, []interface{}{"d", "f"}},
|
||||
{"Values / Invalid params", "INSERT INTO test (a, b, c) VALUES ('d', $1)", true, "", []any{'e'}},
|
||||
{"Values / Positional Params", "INSERT INTO test (pk, a, b, c) VALUES (1, $1, 'e', $2)", false, `[{"a":"d","b":"e","c":"f"}]`, []any{"d", "f"}},
|
||||
{"Values / Invalid params", "INSERT INTO test (pk, a, b, c) VALUES (1, 'd', $1)", true, "", []any{'e'}},
|
||||
{"Select / same table", "INSERT INTO test SELECT * FROM test", true, ``, nil},
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestInsertStmt(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE test(a TEXT, b TEXT, c TEXT)")
|
||||
_, err = db.Exec("CREATE TABLE test(pk INT PRIMARY KEY, a TEXT, b TEXT, c TEXT)")
|
||||
require.NoError(t, err)
|
||||
if withIndexes {
|
||||
_, err = db.Exec(`
|
||||
@@ -46,7 +46,7 @@ func TestInsertStmt(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
rows, err := db.Query("SELECT * FROM test")
|
||||
rows, err := db.Query("SELECT a, b, c FROM test")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.RequireJSONArrayEq(t, rows, test.expected)
|
||||
@@ -62,7 +62,7 @@ func TestInsertStmt(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE test(a INT)`)
|
||||
_, err = db.Exec(`CREATE TABLE test(a INT PRIMARY KEY)`)
|
||||
require.NoError(t, err)
|
||||
|
||||
var a, A int
|
||||
@@ -77,7 +77,7 @@ func TestInsertStmt(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE test(a int unique)`)
|
||||
_, err = db.Exec(`CREATE TABLE test(a int primary key)`)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(`insert into test (a) VALUES (1), (1)`)
|
||||
@@ -116,17 +116,17 @@ func TestInsertStmt(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE test(a INT UNIQUE, b INT)`)
|
||||
_, err = db.Exec(`CREATE TABLE test(pk INT PRIMARY KEY, a INT UNIQUE, b INT)`)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(`insert into test (a, b) VALUES (1, 1)`)
|
||||
_, err = db.Exec(`insert into test (pk, a, b) VALUES (1, 1, 1)`)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(`insert into test (a, b) VALUES (1, 2) ON CONFLICT DO REPLACE`)
|
||||
_, err = db.Exec(`insert into test (pk, a, b) VALUES (2, 1, 2) ON CONFLICT DO REPLACE`)
|
||||
require.NoError(t, err)
|
||||
|
||||
var a, b int
|
||||
err = db.QueryRow(`SELECT * FROM test`).Scan(&a, &b)
|
||||
err = db.QueryRow(`SELECT a, b FROM test`).Scan(&a, &b)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, a)
|
||||
require.Equal(t, 2, b)
|
||||
@@ -164,7 +164,7 @@ func TestInsertSelect(t *testing.T) {
|
||||
{"No columns / No projection", `INSERT INTO foo SELECT * FROM bar`, false, `[{"a":1, "b":10, "c":null, "d":null, "e":null}]`, nil},
|
||||
{"No columns / Projection", `INSERT INTO foo SELECT a FROM bar`, false, `[{"a":1, "b":null, "c":null, "d":null, "e":null}]`, nil},
|
||||
{"With columns / No Projection", `INSERT INTO foo (a, b) SELECT * FROM bar`, true, ``, nil},
|
||||
{"With columns / Projection", `INSERT INTO foo (c, d) SELECT a, b FROM bar`, false, `[{"a":null, "b":null, "c":1, "d":10, "e":null}]`, nil},
|
||||
{"With columns / Projection", `INSERT INTO foo (a, d) SELECT a, b FROM bar`, false, `[{"a":1, "b":null, "c":null, "d":10, "e":null}]`, nil},
|
||||
{"Too many columns / No Projection", `INSERT INTO foo (c) SELECT * FROM bar`, true, ``, nil},
|
||||
{"Too many columns / Projection", `INSERT INTO foo (c, d) SELECT a, b, c FROM bar`, true, ``, nil},
|
||||
{"Too few columns / No Projection", `INSERT INTO foo (c, d, e) SELECT * FROM bar`, true, ``, nil},
|
||||
@@ -178,8 +178,8 @@ func TestInsertSelect(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE foo(a INT, b INT, c INT, d INT, e INT);
|
||||
CREATE TABLE bar(a INT, b INT, c INT, d INT, e INT);
|
||||
CREATE TABLE foo(a INT PRIMARY KEY, b INT, c INT, d INT, e INT);
|
||||
CREATE TABLE bar(a INT PRIMARY KEY, b INT, c INT, d INT, e INT);
|
||||
INSERT INTO bar (a, b) VALUES (1, 10)
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
@@ -28,8 +28,8 @@ func TestReIndex(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, `
|
||||
CREATE TABLE test1(a TEXT, b TEXT);
|
||||
CREATE TABLE test2(a TEXT, b TEXT);
|
||||
CREATE TABLE test1(a TEXT PRIMARY KEY, b TEXT);
|
||||
CREATE TABLE test2(a TEXT PRIMARY KEY, b TEXT);
|
||||
|
||||
CREATE INDEX idx_test1_a ON test1(a);
|
||||
CREATE INDEX idx_test1_b ON test1(b);
|
||||
|
@@ -182,7 +182,7 @@ func TestSelectStmt(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE test(foo INT); CREATE INDEX idx_foo ON test(foo);")
|
||||
_, err = db.Exec("CREATE TABLE test(foo INT PRIMARY KEY); CREATE INDEX idx_foo ON test(foo);")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(`INSERT INTO test (foo) VALUES (4), (2), (1), (3)`)
|
||||
@@ -213,7 +213,7 @@ func TestSelectStmt(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE test(a INT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY);
|
||||
INSERT INTO test (a) VALUES (1);
|
||||
CREATE SEQUENCE seq;
|
||||
`)
|
||||
@@ -238,7 +238,7 @@ func TestSelectStmt(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE test(a INT);
|
||||
CREATE TABLE test(a INT PRIMARY KEY);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3);
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
@@ -39,7 +39,7 @@ func TestUpdateStmt(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE test (a text not null, b text, c text, d text, e text)")
|
||||
_, err = db.Exec("CREATE TABLE test (pk int primary key, a text not null, b text, c text, d text, e text)")
|
||||
require.NoError(t, err)
|
||||
|
||||
if indexed {
|
||||
@@ -47,11 +47,11 @@ func TestUpdateStmt(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO test (a, b, c) VALUES ('foo1', 'bar1', 'baz1')")
|
||||
_, err = db.Exec("INSERT INTO test (pk, a, b, c) VALUES (1, 'foo1', 'bar1', 'baz1')")
|
||||
require.NoError(t, err)
|
||||
_, err = db.Exec("INSERT INTO test (a, b) VALUES ('foo2', 'bar2')")
|
||||
_, err = db.Exec("INSERT INTO test (pk, a, b) VALUES (2, 'foo2', 'bar2')")
|
||||
require.NoError(t, err)
|
||||
_, err = db.Exec("INSERT INTO test (a, d, e) VALUES ('foo3', 'bar3', 'baz3')")
|
||||
_, err = db.Exec("INSERT INTO test (pk, a, d, e) VALUES (3, 'foo3', 'bar3', 'baz3')")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(test.query, test.params...)
|
||||
@@ -61,7 +61,7 @@ func TestUpdateStmt(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
rows, err := db.Query("SELECT * FROM test")
|
||||
rows, err := db.Query("SELECT a, b, c, d, e FROM test")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.RequireJSONArrayEq(t, rows, test.expected)
|
||||
|
@@ -22,7 +22,7 @@ func TestDriver(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
res, err := db.Exec("CREATE TABLE test(a INT, b TEXT, c BOOL)")
|
||||
res, err := db.Exec("CREATE TABLE test(a INT PRIMARY KEY, b TEXT, c BOOL)")
|
||||
require.NoError(t, err)
|
||||
n, err := res.RowsAffected()
|
||||
require.Error(t, err)
|
||||
@@ -243,7 +243,7 @@ func TestDriver(t *testing.T) {
|
||||
INSERT INTO test (a, b, c) VALUES (12, 13, 14);
|
||||
SELECT * FROM test;
|
||||
`)
|
||||
require.EqualError(t, err, "cannot increment sequence on read-only transaction")
|
||||
require.EqualError(t, err, "cannot put in read-only mode")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ func TestDriverWithTimeValues(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
now := time.Now().UTC().Truncate(time.Microsecond)
|
||||
_, err = db.Exec("CREATE TABLE test(a TIMESTAMP); INSERT INTO test (a) VALUES ($1)", now)
|
||||
_, err = db.Exec("CREATE TABLE test(a TIMESTAMP PRIMARY KEY); INSERT INTO test (a) VALUES ($1)", now)
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, err := db.BeginTx(context.Background(), &sql.TxOptions{ReadOnly: true})
|
||||
|
@@ -17,7 +17,7 @@ func TestParserDelete(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(age int)")
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(age int primary key)")
|
||||
|
||||
parseExpr := func(s string) expr.Expr {
|
||||
e := parser.MustParseExpr(s)
|
||||
|
@@ -82,6 +82,14 @@ func (p *Parser) parseSimpleColumnList() ([]string, error) {
|
||||
if columns, err = p.parseIdentList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
set := make(map[string]struct{})
|
||||
for _, c := range columns {
|
||||
_, ok := set[c]
|
||||
if ok {
|
||||
return nil, errors.Errorf("column %q specified more than once", c)
|
||||
}
|
||||
set[c] = struct{}{}
|
||||
}
|
||||
|
||||
// Parse required ) token.
|
||||
if err := p.ParseTokens(scanner.RPAREN); err != nil {
|
||||
|
@@ -217,7 +217,7 @@ func TestParserInsert(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(a TEXT, b TEXT); CREATE TABLE foo(c TEXT, d TEXT);")
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(a TEXT PRIMARY KEY, b TEXT); CREATE TABLE foo(c TEXT PRIMARY KEY, d TEXT);")
|
||||
|
||||
stmts, err := parser.ParseQuery(test.s)
|
||||
if test.fails {
|
||||
|
@@ -19,13 +19,13 @@ func TestParserSelect(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, `
|
||||
CREATE TABLE test(a TEXT, b TEXT, age int);
|
||||
CREATE TABLE test1(age INT, a INT);
|
||||
CREATE TABLE test2(age INT, a INT);
|
||||
CREATE TABLE a(age INT, a INT);
|
||||
CREATE TABLE b(age INT, a INT);
|
||||
CREATE TABLE c(age INT, a INT);
|
||||
CREATE TABLE d(age INT, a INT);
|
||||
CREATE TABLE test(a TEXT PRIMARY KEY, b TEXT, age int);
|
||||
CREATE TABLE test1(age INT PRIMARY KEY, a INT);
|
||||
CREATE TABLE test2(age INT PRIMARY KEY, a INT);
|
||||
CREATE TABLE a(age INT PRIMARY KEY, a INT);
|
||||
CREATE TABLE b(age INT PRIMARY KEY, a INT);
|
||||
CREATE TABLE c(age INT PRIMARY KEY, a INT);
|
||||
CREATE TABLE d(age INT PRIMARY KEY, a INT);
|
||||
`,
|
||||
)
|
||||
|
||||
|
@@ -18,7 +18,7 @@ func TestParserUpdate(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(a INT, b TEXT)")
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(pk INT PRIMARY KEY, a INT, b TEXT)")
|
||||
|
||||
parseExpr := func(s string, table ...string) expr.Expr {
|
||||
e := parser.MustParseExpr(s)
|
||||
|
@@ -120,7 +120,7 @@ func (it *DeleteIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *DeleteIterator) Row() (database.Row, error) {
|
||||
return it.row, it.err
|
||||
return it.row, it.Error()
|
||||
}
|
||||
|
||||
func (it *DeleteIterator) Error() error {
|
||||
|
@@ -119,13 +119,5 @@ func (it *InsertIterator) Error() error {
|
||||
}
|
||||
|
||||
func (it *InsertIterator) Row() (database.Row, error) {
|
||||
if it.err != nil {
|
||||
return nil, it.err
|
||||
}
|
||||
|
||||
if it.row != nil {
|
||||
return it.row, nil
|
||||
}
|
||||
|
||||
return it.Iterator.Row()
|
||||
return it.row, it.Error()
|
||||
}
|
||||
|
@@ -68,19 +68,19 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"no range", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": null, "c": null}`, `{"a": 2, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": null, "c": null}`, `{"pk": 2, "a": 2, "b": null, "c": null}`),
|
||||
nil, false, false,
|
||||
},
|
||||
{
|
||||
"no range", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2}`, `{"a": 2, "b": 3}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2, "c": null}`, `{"a": 2, "b": 3, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": 2, "c": null}`, `{"pk": 2, "a": 2, "b": 3, "c": null}`),
|
||||
nil, false, false,
|
||||
},
|
||||
{
|
||||
"max:2", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": null, "c": null}`, `{"a": 2, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": null, "c": null}`, `{"pk": 2, "a": 2, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Max: testutil.ExprList(t, `(2)`), Columns: []string{"a"}},
|
||||
},
|
||||
@@ -98,7 +98,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"max:(2, 2)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": 2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": 2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Max: testutil.ExprList(t, `(2, 2)`), Columns: []string{"a", "b"}},
|
||||
},
|
||||
@@ -116,7 +116,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"max:1", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Max: testutil.ExprList(t, `(1)`), Columns: []string{"a"}},
|
||||
},
|
||||
@@ -125,7 +125,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"max:(1, 2)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": 2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Max: testutil.ExprList(t, `(1, 2)`), Columns: []string{"a", "b"}},
|
||||
},
|
||||
@@ -143,7 +143,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": null, "c": null}`, `{"a": 2, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": null, "c": null}`, `{"pk": 2, "a": 2, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a"}},
|
||||
},
|
||||
@@ -152,7 +152,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(1),exclusive", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a"}, Exclusive: true},
|
||||
},
|
||||
@@ -161,7 +161,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(1),exclusive", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": 2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": 2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a", "b"}, Exclusive: true},
|
||||
},
|
||||
@@ -170,7 +170,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(2, 1)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": 2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": 2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(2, 1)`),
|
||||
@@ -194,7 +194,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min/max", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": null, "c": null}`, `{"a": 2, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": null, "c": null}`, `{"pk": 2, "a": 2, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1)`),
|
||||
@@ -207,7 +207,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(1, 1), max:[2,2]", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2, "c": null}`, `{"a": 2, "b": 2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": 2, "c": null}`, `{"pk": 2, "a": 2, "b": 2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1, 1)`),
|
||||
@@ -220,7 +220,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(1, 1), max:[2,2] bis", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 3}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 3, "c": null}`, `{"a": 2, "b": 2, "c": null}`), // [1, 3] < (2, 2)
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": 3, "c": null}`, `{"pk": 2, "a": 2, "b": 2, "c": null}`), // [1, 3] < (2, 2)
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1, 1)`),
|
||||
@@ -233,13 +233,13 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse/no range", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": null, "c": null}`, `{"a": 1, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": null, "c": null}`, `{"pk": 1, "a": 1, "b": null, "c": null}`),
|
||||
nil, true, false,
|
||||
},
|
||||
{
|
||||
"reverse/max", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": null, "c": null}`, `{"a": 1, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": null, "c": null}`, `{"pk": 1, "a": 1, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Max: testutil.ExprList(t, `(2)`), Columns: []string{"a"}},
|
||||
},
|
||||
@@ -248,7 +248,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse/max", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": 2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": 2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Max: testutil.ExprList(t, `(2, 2)`),
|
||||
@@ -260,7 +260,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse/min", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": null, "c": null}`, `{"a": 1, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": null, "c": null}`, `{"pk": 1, "a": 1, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a"}},
|
||||
},
|
||||
@@ -269,7 +269,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse/min neg", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": -2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a"}},
|
||||
},
|
||||
@@ -278,7 +278,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse/min", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": 1, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1, 1)`),
|
||||
@@ -290,7 +290,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse/min/max", "a",
|
||||
testutil.MakeRows(t, `{"a": 1}`, `{"a": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": null, "c": null}`, `{"a": 1, "b": null, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": null, "c": null}`, `{"pk": 1, "a": 1, "b": null, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1)`),
|
||||
@@ -303,7 +303,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse/min/max", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1}`, `{"a": 2, "b": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": 2, "c": null}`, `{"a": 1, "b": 1, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 2, "a": 2, "b": 2, "c": null}`, `{"pk": 1, "a": 1, "b": 1, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1, 1)`),
|
||||
@@ -316,7 +316,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"max:(1)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1}`, `{"a": 2, "b": 2}`, `{"a": 1, "b": 9223372036854775807}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1, "c": null}`, `{"a": 1, "b": 9223372036854775807, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": 1, "c": null}`, `{"pk": 3, "a": 1, "b": 9223372036854775807, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Max: testutil.ExprList(t, `(1)`),
|
||||
@@ -328,7 +328,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse max:(1)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1}`, `{"a": 2, "b": 2}`, `{"a": 1, "b": 9223372036854775807}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 9223372036854775807, "c": null}`, `{"a": 1, "b": 1, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 3, "a": 1, "b": 9223372036854775807, "c": null}`, `{"pk": 1, "a": 1, "b": 1, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Max: testutil.ExprList(t, `(1)`),
|
||||
@@ -342,7 +342,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"max:(1, 2)", "a, b, c",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2, "c": 1}`, `{"a": 2, "b": 2, "c": 2}`, `{"a": 1, "b": 2, "c": 9223372036854775807}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 2, "c": 1}`, `{"a": 1, "b": 2, "c": 9223372036854775807}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": 2, "c": 1}`, `{"pk": 3, "a": 1, "b": 2, "c": 9223372036854775807}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Max: testutil.ExprList(t, `(1, 2)`), Columns: []string{"a", "b", "c"},
|
||||
@@ -353,7 +353,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(1)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2}`, `{"a": -2, "b": 2}`, `{"a": 1, "b": 1}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2, "c": null}`, `{"a": 1, "b": 1, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": -2, "c": null}`, `{"pk": 3, "a": 1, "b": 1, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a", "b"}},
|
||||
},
|
||||
@@ -362,7 +362,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(1)", "a, b, c",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2, "c": 0}`, `{"a": -2, "b": 2, "c": 1}`, `{"a": 1, "b": 1, "c": 2}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2, "c": 0}`, `{"a": 1, "b": 1, "c": 2}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": -2, "c": 0}`, `{"pk": 3, "a": 1, "b": 1, "c": 2}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a", "b", "c"}},
|
||||
},
|
||||
@@ -371,7 +371,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse min:(1)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2}`, `{"a": -2, "b": 2}`, `{"a": 1, "b": 1}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": 1, "c": null}`, `{"a": 1, "b": -2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 3, "a": 1, "b": 1, "c": null}`, `{"pk": 1, "a": 1, "b": -2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{Min: testutil.ExprList(t, `(1)`), Columns: []string{"a", "b"}},
|
||||
},
|
||||
@@ -380,7 +380,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"min:(1), max(2)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2}`, `{"a": -2, "b": 2}`, `{"a": 2, "b": 42}`, `{"a": 3, "b": -1}`),
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2, "c": null}`, `{"a": 2, "b": 42, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 1, "a": 1, "b": -2, "c": null}`, `{"pk": 3, "a": 2, "b": 42, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1)`),
|
||||
@@ -393,7 +393,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
{
|
||||
"reverse min:(1), max(2)", "a, b",
|
||||
testutil.MakeRows(t, `{"a": 1, "b": -2}`, `{"a": -2, "b": 2}`, `{"a": 2, "b": 42}`, `{"a": 3, "b": -1}`),
|
||||
testutil.MakeRows(t, `{"a": 2, "b": 42, "c": null}`, `{"a": 1, "b": -2, "c": null}`),
|
||||
testutil.MakeRows(t, `{"pk": 3, "a": 2, "b": 42, "c": null}`, `{"pk": 1, "a": 1, "b": -2, "c": null}`),
|
||||
stream.Ranges{
|
||||
stream.Range{
|
||||
Min: testutil.ExprList(t, `(1)`),
|
||||
@@ -410,7 +410,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test (a BIGINT, b BIGINT, c BIGINT);")
|
||||
testutil.MustExec(t, db, tx, "CREATE SEQUENCE seq; CREATE TABLE test (pk INT PRIMARY KEY DEFAULT nextval('seq'), a BIGINT, b BIGINT, c BIGINT);")
|
||||
|
||||
for _, r := range test.rowsInTable {
|
||||
var a, b, c *int64
|
||||
@@ -430,7 +430,7 @@ func testIndexScan(t *testing.T, getOp func(db *database.Database, tx *database.
|
||||
x := types.AsInt64(v)
|
||||
c = &x
|
||||
}
|
||||
testutil.MustExec(t, db, tx, "INSERT INTO test VALUES ($1, $2, $3)", environment.Param{Value: a}, environment.Param{Value: b}, environment.Param{Value: c})
|
||||
testutil.MustExec(t, db, tx, "INSERT INTO test (a, b, c) VALUES ($1, $2, $3)", environment.Param{Value: a}, environment.Param{Value: b}, environment.Param{Value: c})
|
||||
}
|
||||
|
||||
op := getOp(db, tx, "idx_test_a", test.indexOn, test.reverse, test.ranges...)
|
||||
|
@@ -177,9 +177,13 @@ func (it *ValidateIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *ValidateIterator) Row() (database.Row, error) {
|
||||
return it.row, it.err
|
||||
return it.row, it.Error()
|
||||
}
|
||||
|
||||
func (it *ValidateIterator) Error() error {
|
||||
return it.err
|
||||
if it.err != nil {
|
||||
return it.err
|
||||
}
|
||||
|
||||
return it.Iterator.Error()
|
||||
}
|
||||
|
@@ -184,7 +184,7 @@ func TestTableInsert(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test (a INTEGER)")
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test (a INTEGER PRIMARY KEY)")
|
||||
|
||||
in := environment.New(nil, tx, nil, nil)
|
||||
|
||||
|
@@ -270,9 +270,13 @@ func (it *GroupAggregatorIterator) iterateOnPrev() (bool, error) {
|
||||
}
|
||||
|
||||
func (it *GroupAggregatorIterator) Row() (database.Row, error) {
|
||||
return it.row, it.err
|
||||
return it.row, it.Error()
|
||||
}
|
||||
|
||||
func (it *GroupAggregatorIterator) Error() error {
|
||||
return it.err
|
||||
if it.err != nil {
|
||||
return it.err
|
||||
}
|
||||
|
||||
return it.prev.Error()
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ func TestAggregate(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(a int)")
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(a int primary key)")
|
||||
|
||||
for _, val := range test.in {
|
||||
testutil.MustExec(t, db, tx, "INSERT INTO test VALUES ($1)", environment.Param{Value: val})
|
||||
|
@@ -130,7 +130,7 @@ func (it *ExprIterator) Error() error {
|
||||
}
|
||||
|
||||
func (it *ExprIterator) Row() (database.Row, error) {
|
||||
return it.row, nil
|
||||
return it.row, it.err
|
||||
}
|
||||
|
||||
type ProjectIterator struct {
|
||||
@@ -188,7 +188,11 @@ func (it *ProjectIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *ProjectIterator) Error() error {
|
||||
return it.err
|
||||
if it.err != nil {
|
||||
return it.err
|
||||
}
|
||||
|
||||
return it.Iterator.Error()
|
||||
}
|
||||
|
||||
func (it *ProjectIterator) Row() (database.Row, error) {
|
||||
|
@@ -62,18 +62,34 @@ func (op *TempTreeSortOperator) String() string {
|
||||
}
|
||||
|
||||
func encodeTempRow(buf []byte, r row.Row) ([]byte, error) {
|
||||
var values []types.Value
|
||||
// encode each column directly into buf: column name, type, value
|
||||
err := r.Iterate(func(column string, v types.Value) error {
|
||||
values = append(values, types.NewTextValue(column))
|
||||
values = append(values, types.NewIntegerValue(int32(v.Type())))
|
||||
values = append(values, v)
|
||||
// encode column name as text
|
||||
var e error
|
||||
buf, e = types.NewTextValue(column).EncodeAsKey(buf)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
// encode the type as an integer value
|
||||
buf, e = types.NewIntegerValue(int32(v.Type())).EncodeAsKey(buf)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
// encode the value itself
|
||||
buf, e = v.EncodeAsKey(buf)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to iterate row")
|
||||
}
|
||||
|
||||
return types.EncodeValuesAsKey(buf, values...)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func decodeTempRow(b []byte) row.Row {
|
||||
@@ -227,7 +243,15 @@ func (it *TempTreeSortIterator) iterateOnStream() error {
|
||||
}
|
||||
|
||||
func (it *TempTreeSortIterator) Error() error {
|
||||
return it.err
|
||||
if it.err != nil {
|
||||
return it.err
|
||||
}
|
||||
|
||||
if it.tempIt != nil {
|
||||
return it.tempIt.Error()
|
||||
}
|
||||
|
||||
return it.prev.Error()
|
||||
}
|
||||
|
||||
func (it *TempTreeSortIterator) Row() (database.Row, error) {
|
||||
|
@@ -55,25 +55,15 @@ func TestTempTreeSort(t *testing.T) {
|
||||
db, tx, cleanup := testutil.NewTestTx(t)
|
||||
defer cleanup()
|
||||
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(a int)")
|
||||
testutil.MustExec(t, db, tx, "CREATE TABLE test(pk int primary key, a int)")
|
||||
|
||||
for _, val := range test.values {
|
||||
testutil.MustExec(t, db, tx, "INSERT INTO test VALUES ($1)", environment.Param{Value: val})
|
||||
for i, val := range test.values {
|
||||
testutil.MustExec(t, db, tx, "INSERT INTO test (pk, a) VALUES ($1, $2)", environment.Param{Value: i + 1}, environment.Param{Value: val})
|
||||
}
|
||||
|
||||
err := testutil.MustQuery(t, db, tx, "SELECT * FROM test").Iterate(func(r database.Row) error {
|
||||
d, err := row.MarshalJSON(r)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Log(string(d))
|
||||
return nil
|
||||
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
env := environment.New(db, tx, nil, nil)
|
||||
|
||||
s := stream.New(table.Scan("test"))
|
||||
s := stream.New(table.Scan("test")).Pipe(rows.Project(parser.MustParseExpr("a")))
|
||||
if test.desc {
|
||||
s = s.Pipe(rows.TempTreeSortReverse(test.sortExpr))
|
||||
} else {
|
||||
@@ -81,9 +71,9 @@ func TestTempTreeSort(t *testing.T) {
|
||||
}
|
||||
|
||||
var got []row.Row
|
||||
err = s.Iterate(env, func(r database.Row) error {
|
||||
err := s.Iterate(env, func(r database.Row) error {
|
||||
fb := row.NewColumnBuffer()
|
||||
err = fb.Copy(r)
|
||||
err := fb.Copy(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -81,10 +81,7 @@ func (it *DeleteIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *DeleteIterator) Row() (database.Row, error) {
|
||||
if it.err != nil {
|
||||
return nil, it.err
|
||||
}
|
||||
return it.row, nil
|
||||
return it.row, it.Error()
|
||||
}
|
||||
|
||||
func (it *DeleteIterator) Error() error {
|
||||
|
@@ -90,7 +90,7 @@ func (it *InsertIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *InsertIterator) Row() (database.Row, error) {
|
||||
return it.row, it.err
|
||||
return it.row, it.Error()
|
||||
}
|
||||
|
||||
func (it *InsertIterator) Error() error {
|
||||
|
@@ -130,7 +130,7 @@ func (it *GenerateKeyIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *GenerateKeyIterator) Row() (database.Row, error) {
|
||||
return &it.br, it.err
|
||||
return &it.br, it.Error()
|
||||
}
|
||||
|
||||
func (it *GenerateKeyIterator) Error() error {
|
||||
@@ -142,16 +142,11 @@ func (it *GenerateKeyIterator) Error() error {
|
||||
}
|
||||
|
||||
func (it *GenerateKeyIterator) generateKey(r database.Row) (*tree.Key, error) {
|
||||
var isRowid bool
|
||||
k, isRowid, err := it.table.GenerateKey(r)
|
||||
k, err := it.table.GenerateKey(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isRowid {
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// check if the primary key already exists
|
||||
exists, err := it.table.Exists(k)
|
||||
if err != nil {
|
||||
|
@@ -74,10 +74,7 @@ func (it *ReplaceIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *ReplaceIterator) Row() (database.Row, error) {
|
||||
if it.err != nil {
|
||||
return nil, it.err
|
||||
}
|
||||
return it.row, nil
|
||||
return it.row, it.Error()
|
||||
}
|
||||
|
||||
func (it *ReplaceIterator) Error() error {
|
||||
|
@@ -114,7 +114,7 @@ func (it *ValidateIterator) Next() bool {
|
||||
}
|
||||
|
||||
func (it *ValidateIterator) Row() (database.Row, error) {
|
||||
return &it.br, it.err
|
||||
return &it.br, it.Error()
|
||||
}
|
||||
|
||||
func (it *ValidateIterator) Error() error {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a int);
|
||||
CREATE TABLE test(a int primary key);
|
||||
|
||||
-- test: column constraints are updated
|
||||
INSERT INTO test VALUES (1), (2);
|
||||
@@ -8,7 +8,7 @@ SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, b INTEGER DEFAULT 0)"
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL, b INTEGER DEFAULT 0, CONSTRAINT test_pk PRIMARY KEY (a))"
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -75,47 +75,22 @@ INSERT INTO test VALUES (1), (2);
|
||||
-- test: primary key: with data
|
||||
INSERT INTO test VALUES (1), (2);
|
||||
ALTER TABLE test ADD COLUMN b int PRIMARY KEY;
|
||||
-- error: NOT NULL constraint error: [b]
|
||||
-- error: multiple primary keys for table "test" are not allowed
|
||||
|
||||
-- test: primary key: without data
|
||||
ALTER TABLE test ADD COLUMN b int PRIMARY KEY;
|
||||
INSERT INTO test VALUES (1, 10), (2, 20);
|
||||
SELECT a, b FROM test;
|
||||
/* result:
|
||||
{
|
||||
"a": 1,
|
||||
"b": 10
|
||||
}
|
||||
{
|
||||
"a": 2,
|
||||
"b": 20
|
||||
}
|
||||
*/
|
||||
-- error: multiple primary keys for table "test" are not allowed
|
||||
|
||||
-- test: primary key: with default: with data
|
||||
INSERT INTO test VALUES (1), (2);
|
||||
ALTER TABLE test ADD COLUMN b int PRIMARY KEY DEFAULT 10;
|
||||
-- error: PRIMARY KEY constraint error: [b]
|
||||
-- error: multiple primary keys for table "test" are not allowed
|
||||
|
||||
-- test: primary key: with default: without data
|
||||
ALTER TABLE test ADD COLUMN b int PRIMARY KEY DEFAULT 10;
|
||||
INSERT INTO test VALUES (2, 20), (3, 30);
|
||||
INSERT INTO test (a) VALUES (1);
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
{
|
||||
"a": 1,
|
||||
"b": 10
|
||||
}
|
||||
{
|
||||
"a": 2,
|
||||
"b": 20
|
||||
}
|
||||
{
|
||||
"a": 3,
|
||||
"b": 30
|
||||
}
|
||||
*/
|
||||
-- error:
|
||||
|
||||
-- test: bad syntax: no type
|
||||
INSERT INTO test VALUES (1), (2);
|
||||
|
@@ -16,7 +16,7 @@ ALTER TABLE unknown RENAME TO test2;
|
||||
-- error:
|
||||
|
||||
-- test: duplicate
|
||||
CREATE TABLE test2;
|
||||
CREATE TABLE test2(a int primary key);
|
||||
ALTER TABLE test2 RENAME TO test;
|
||||
-- error:
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- setup:
|
||||
CREATE TABLE test (a int);
|
||||
CREATE TABLE test (a int primary key);
|
||||
|
||||
-- test: named index
|
||||
CREATE INDEX test_a_idx ON test(a);
|
||||
|
@@ -1,14 +1,14 @@
|
||||
-- test: undeclared column
|
||||
CREATE TABLE test;
|
||||
CREATE INDEX test_a_idx ON test(a);
|
||||
CREATE TABLE test (a int primary key);
|
||||
CREATE INDEX test_b_idx ON test(b);
|
||||
-- error:
|
||||
|
||||
-- test: undeclared column: IF NOT EXISTS
|
||||
CREATE TABLE test;
|
||||
CREATE INDEX IF NOT EXISTS test_a_idx ON test(a);
|
||||
CREATE TABLE test (a int primary key);
|
||||
CREATE INDEX IF NOT EXISTS test_b_idx ON test(b);
|
||||
-- error:
|
||||
|
||||
-- test: undeclared column: other columns
|
||||
CREATE TABLE test(b int);
|
||||
CREATE TABLE test(b int primary key);
|
||||
CREATE INDEX test_a_idx ON test(a);
|
||||
-- error:
|
||||
|
@@ -1,36 +1,36 @@
|
||||
-- test: basic
|
||||
CREATE TABLE test(a int);
|
||||
CREATE TABLE test(a int primary key);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: duplicate
|
||||
CREATE TABLE test(a int);
|
||||
CREATE TABLE test(a int);
|
||||
CREATE TABLE test(a int primary key);
|
||||
CREATE TABLE test(a int primary key);
|
||||
-- error:
|
||||
|
||||
-- test: if not exists
|
||||
CREATE TABLE test(a int);
|
||||
CREATE TABLE IF NOT EXISTS test(b int);
|
||||
CREATE TABLE test(a int primary key);
|
||||
CREATE TABLE IF NOT EXISTS test(b int primary key);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: if not exists, twice
|
||||
CREATE TABLE IF NOT EXISTS test(a int);
|
||||
CREATE TABLE IF NOT EXISTS test(a int);
|
||||
CREATE TABLE IF NOT EXISTS test(a int primary key);
|
||||
CREATE TABLE IF NOT EXISTS test(a int primary key);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a))"
|
||||
}
|
||||
*/
|
||||
|
@@ -1,13 +1,13 @@
|
||||
-- test: as column constraint
|
||||
CREATE TABLE test (
|
||||
a INT CHECK(a > 10 AND a < 20)
|
||||
a INT PRIMARY KEY CHECK(a > 10 AND a < 20)
|
||||
);
|
||||
SELECT name, type, sql FROM __chai_catalog WHERE name = "test";
|
||||
/* result:
|
||||
{
|
||||
name: "test",
|
||||
type: "table",
|
||||
sql: "CREATE TABLE test (a INTEGER, CONSTRAINT test_check CHECK (a > 10 AND a < 20))"
|
||||
sql: "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a), CONSTRAINT test_check CHECK (a > 10 AND a < 20))"
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -32,26 +32,26 @@ SELECT name, type, sql FROM __chai_catalog WHERE name = "test";
|
||||
|
||||
-- test: as column constraint, no parentheses
|
||||
CREATE TABLE test (
|
||||
a INT CHECK a > 10
|
||||
a INT PRIMARY KEY CHECK a > 10
|
||||
);
|
||||
-- error:
|
||||
|
||||
-- test: as column constraint, incompatible default value
|
||||
CREATE TABLE test (
|
||||
a INT CHECK (a > 10) DEFAULT 0
|
||||
a INT PRIMARY KEY CHECK (a > 10) DEFAULT 0
|
||||
);
|
||||
SELECT name, type, sql FROM __chai_catalog WHERE name = "test";
|
||||
/* result:
|
||||
{
|
||||
name: "test",
|
||||
type: "table",
|
||||
sql: "CREATE TABLE test (a INTEGER DEFAULT 0, CONSTRAINT test_check CHECK (a > 10))"
|
||||
sql: "CREATE TABLE test (a INTEGER NOT NULL DEFAULT 0, CONSTRAINT test_pk PRIMARY KEY (a), CONSTRAINT test_check CHECK (a > 10))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: as column constraint, reference other columns
|
||||
CREATE TABLE test (
|
||||
a INT CHECK (a > 10 AND b < 10),
|
||||
a INT PRIMARY KEY CHECK (a > 10 AND b < 10),
|
||||
b INT
|
||||
);
|
||||
SELECT name, type, sql FROM __chai_catalog WHERE name = "test";
|
||||
@@ -59,13 +59,13 @@ SELECT name, type, sql FROM __chai_catalog WHERE name = "test";
|
||||
{
|
||||
name: "test",
|
||||
type: "table",
|
||||
sql: "CREATE TABLE test (a INTEGER, b INTEGER, CONSTRAINT test_check CHECK (a > 10 AND b < 10))"
|
||||
sql: "CREATE TABLE test (a INTEGER NOT NULL, b INTEGER, CONSTRAINT test_pk PRIMARY KEY (a), CONSTRAINT test_check CHECK (a > 10 AND b < 10))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: as table constraint
|
||||
CREATE TABLE test (
|
||||
a INT,
|
||||
a INT PRIMARY KEY,
|
||||
CHECK (a > 10),
|
||||
CHECK (a > 20)
|
||||
);
|
||||
@@ -74,6 +74,6 @@ SELECT name, type, sql FROM __chai_catalog WHERE name = "test";
|
||||
{
|
||||
name: "test",
|
||||
type: "table",
|
||||
sql: "CREATE TABLE test (a INTEGER, CONSTRAINT test_check CHECK (a > 10), CONSTRAINT test_check1 CHECK (a > 20))"
|
||||
sql: "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a), CONSTRAINT test_check CHECK (a > 10), CONSTRAINT test_check1 CHECK (a > 20))"
|
||||
}
|
||||
*/
|
||||
|
@@ -1,50 +1,50 @@
|
||||
-- test: type
|
||||
CREATE TABLE test(a INTEGER);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INTEGER);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: NOT NULL
|
||||
CREATE TABLE test(a INT NOT NULL);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT NOT NULL);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: default
|
||||
CREATE TABLE test(a INT DEFAULT 10);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT DEFAULT 10);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER DEFAULT 10)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER DEFAULT 10, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: unique
|
||||
CREATE TABLE test(a INT UNIQUE);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT UNIQUE);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, CONSTRAINT test_a_unique UNIQUE (a))"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk), CONSTRAINT test_a_unique UNIQUE (a))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: check
|
||||
CREATE TABLE test(a INT CHECK(a > 10));
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT CHECK(a > 10));
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, CONSTRAINT test_check CHECK (a > 10))"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk), CONSTRAINT test_check CHECK (a > 10))"
|
||||
}
|
||||
*/
|
||||
|
||||
|
@@ -1,129 +1,157 @@
|
||||
-- test: same type
|
||||
CREATE TABLE test(a INT DEFAULT 10);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT DEFAULT 10);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER DEFAULT 10)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER DEFAULT 10, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: compatible type
|
||||
CREATE TABLE test(a DOUBLE DEFAULT 10);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 10);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a DOUBLE DEFAULT 10)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a DOUBLE DEFAULT 10, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: expr
|
||||
CREATE TABLE test(a DOUBLE DEFAULT 1 + 4 / 4);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 1 + 4 / 4);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a DOUBLE DEFAULT 1 + 4 / 4)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a DOUBLE DEFAULT 1 + 4 / 4, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: incompatible type
|
||||
CREATE TABLE test(a DOUBLE DEFAULT 'hello');
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 'hello');
|
||||
-- error:
|
||||
|
||||
-- test: function
|
||||
CREATE TABLE test(a DOUBLE DEFAULT pk());
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT pk());
|
||||
-- error:
|
||||
-- test: same type
|
||||
CREATE TABLE test(a INT DEFAULT 10);
|
||||
|
||||
-- test: compatible type
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 10);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER DEFAULT 10)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a DOUBLE DEFAULT 10, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: expr
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 1 + 4 / 4);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a DOUBLE DEFAULT 1 + 4 / 4, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: incompatible type
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 'hello');
|
||||
-- error:
|
||||
|
||||
-- test: function
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT pk());
|
||||
-- error:
|
||||
-- test: same type
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT DEFAULT 10);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER DEFAULT 10, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: compatible type
|
||||
CREATE TABLE test(a DOUBLE DEFAULT 10);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 10);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a DOUBLE DEFAULT 10)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a DOUBLE DEFAULT 10, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: expr
|
||||
CREATE TABLE test(a DOUBLE DEFAULT 1 + 4 / 4);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 1 + 4 / 4);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a DOUBLE DEFAULT 1 + 4 / 4)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a DOUBLE DEFAULT 1 + 4 / 4, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: incompatible type
|
||||
CREATE TABLE test(a DOUBLE DEFAULT 'hello');
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT 'hello');
|
||||
-- error:
|
||||
|
||||
-- test: function
|
||||
CREATE TABLE test(a DOUBLE DEFAULT pk());
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a DOUBLE DEFAULT pk());
|
||||
-- error:
|
||||
|
||||
-- test: incompatible expr
|
||||
CREATE TABLE test(a BLOB DEFAULT 1 + 4 / 4);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a BLOB DEFAULT 1 + 4 / 4);
|
||||
-- error:
|
||||
|
||||
-- test: forbidden tokens: AND
|
||||
CREATE TABLE test(a BLOB DEFAULT 1 AND 1);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a BLOB DEFAULT 1 AND 1);
|
||||
-- error:
|
||||
|
||||
-- test: forbidden tokens: path
|
||||
CREATE TABLE test(a BLOB DEFAULT b);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a BLOB DEFAULT b);
|
||||
-- error:
|
||||
|
||||
-- test: DEFAULT nextval sequence
|
||||
CREATE SEQUENCE seq1;
|
||||
CREATE TABLE test(a INTEGER DEFAULT nextval('seq1'));
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INTEGER DEFAULT nextval('seq1'));
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER DEFAULT nextval(\"seq1\"))"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER DEFAULT nextval(\"seq1\"), CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: DEFAULT with parentheses
|
||||
CREATE TABLE test(a INTEGER DEFAULT (1 + 2));
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INTEGER DEFAULT (1 + 2));
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER DEFAULT 1 + 2)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER DEFAULT 1 + 2, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: DEFAULT (nextval sequence)
|
||||
CREATE SEQUENCE seq_paren;
|
||||
CREATE TABLE test(a INTEGER DEFAULT (nextval('seq_paren')));
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INTEGER DEFAULT (nextval('seq_paren')));
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER DEFAULT nextval(\"seq_paren\"))"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER DEFAULT nextval(\"seq_paren\"), CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: DEFAULT with nested parentheses
|
||||
CREATE TABLE test(a INTEGER DEFAULT ((1)));
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INTEGER DEFAULT ((1)));
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER DEFAULT (1))"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER DEFAULT (1), CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
-- test: basic
|
||||
CREATE TABLE test(a INTEGER NOT NULL);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INTEGER NOT NULL);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: not null twice
|
||||
CREATE TABLE test(a INT NOT NULL NOT NULL);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT NOT NULL NOT NULL);
|
||||
-- error:
|
||||
|
@@ -1,143 +1,153 @@
|
||||
-- test: INTEGER
|
||||
CREATE TABLE test (a INTEGER);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a INTEGER);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: BIGINT
|
||||
CREATE TABLE test (a BIGINT);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a BIGINT);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a BIGINT)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a BIGINT, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: DOUBLE
|
||||
CREATE TABLE test (a DOUBLE);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a DOUBLE);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a DOUBLE)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a DOUBLE, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: BOOLEAN
|
||||
CREATE TABLE test (a BOOLEAN);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a BOOLEAN);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a BOOLEAN)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a BOOLEAN, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: BLOB
|
||||
CREATE TABLE test (a BLOB);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a BLOB);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a BLOB)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a BLOB, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: TEXT
|
||||
CREATE TABLE test (a TEXT);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a TEXT);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a TEXT)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a TEXT, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: duplicate type
|
||||
CREATE TABLE test (a INT, a TEXT);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a INT, a TEXT);
|
||||
-- error:
|
||||
|
||||
-- test: INTEGER ALIAS: INT
|
||||
CREATE TABLE test (a INT);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a INT);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: INT ALIAS: TINYINT
|
||||
CREATE TABLE test (a INTEGER);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a TINYINT);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: INT ALIAS: mediumint
|
||||
CREATE TABLE test (a mediumint);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a INTEGER);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: INT ALIAS: mediumint
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a mediumint);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: INT ALIAS: INT2
|
||||
CREATE TABLE test (a int2);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a int2);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: BIGINT ALIAS: INT8
|
||||
CREATE TABLE test (a int8);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a int8);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a BIGINT)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a BIGINT, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: BOOLEAN ALIAS: BOOL
|
||||
CREATE TABLE test (a BOOL);
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a BOOL);
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a BOOLEAN)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a BOOLEAN, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: TEXT ALIAS: VARCHAR(n)
|
||||
CREATE TABLE test (a VARCHAR(255));
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a VARCHAR(255));
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a TEXT)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a TEXT, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
||||
-- test: TEXT ALIAS: character(n)
|
||||
CREATE TABLE test (a character(255));
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a character(255));
|
||||
SELECT name, sql FROM __chai_catalog WHERE type = "table" AND name = "test";
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a TEXT)"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a TEXT, CONSTRAINT test_pk PRIMARY KEY (pk))"
|
||||
}
|
||||
*/
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- test: with type
|
||||
CREATE TABLE test(a INT UNIQUE);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT UNIQUE);
|
||||
SELECT name, sql
|
||||
FROM __chai_catalog
|
||||
WHERE
|
||||
@@ -9,7 +9,7 @@ WHERE
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, CONSTRAINT test_a_unique UNIQUE (a))"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, CONSTRAINT test_pk PRIMARY KEY (pk), CONSTRAINT test_a_unique UNIQUE (a))"
|
||||
}
|
||||
{
|
||||
"name": "test_a_idx",
|
||||
@@ -18,7 +18,7 @@ WHERE
|
||||
*/
|
||||
|
||||
-- test: multiple
|
||||
CREATE TABLE test(a INT UNIQUE, b DOUBLE UNIQUE);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT UNIQUE, b DOUBLE UNIQUE);
|
||||
SELECT name, sql
|
||||
FROM __chai_catalog
|
||||
WHERE
|
||||
@@ -28,7 +28,7 @@ WHERE
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, b DOUBLE, CONSTRAINT test_a_unique UNIQUE (a), CONSTRAINT test_b_unique UNIQUE (b))"
|
||||
"sql": "CREATE TABLE test (pk INTEGER NOT NULL, a INTEGER, b DOUBLE, CONSTRAINT test_pk PRIMARY KEY (pk), CONSTRAINT test_a_unique UNIQUE (a), CONSTRAINT test_b_unique UNIQUE (b))"
|
||||
}
|
||||
{
|
||||
"name": "test_a_idx",
|
||||
@@ -41,7 +41,7 @@ WHERE
|
||||
*/
|
||||
|
||||
-- test: table constraint: one column
|
||||
CREATE TABLE test(a INT, UNIQUE(a));
|
||||
CREATE TABLE test(a INT PRIMARY KEY, UNIQUE(a));
|
||||
SELECT name, sql
|
||||
FROM __chai_catalog
|
||||
WHERE
|
||||
@@ -51,7 +51,7 @@ WHERE
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, CONSTRAINT test_a_unique UNIQUE (a))"
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL, CONSTRAINT test_pk PRIMARY KEY (a), CONSTRAINT test_a_unique UNIQUE (a))"
|
||||
}
|
||||
{
|
||||
"name": "test_a_idx",
|
||||
@@ -60,7 +60,7 @@ WHERE
|
||||
*/
|
||||
|
||||
-- test: table constraint: multiple columns
|
||||
CREATE TABLE test(a INT, b INT, UNIQUE(a, b));
|
||||
CREATE TABLE test(a INT PRIMARY KEY, b INT, UNIQUE(a, b));
|
||||
SELECT name, sql
|
||||
FROM __chai_catalog
|
||||
WHERE
|
||||
@@ -70,7 +70,7 @@ WHERE
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, b INTEGER, CONSTRAINT test_a_b_unique UNIQUE (a, b))"
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL, b INTEGER, CONSTRAINT test_pk PRIMARY KEY (a), CONSTRAINT test_a_b_unique UNIQUE (a, b))"
|
||||
}
|
||||
{
|
||||
"name": "test_a_b_idx",
|
||||
@@ -79,7 +79,7 @@ WHERE
|
||||
*/
|
||||
|
||||
-- test: table constraint: multiple columns with order
|
||||
CREATE TABLE test(a INT, b INT, c INT, UNIQUE(a DESC, b ASC, c));
|
||||
CREATE TABLE test(a INT PRIMARY KEY, b INT, c INT, UNIQUE(a DESC, b ASC, c));
|
||||
SELECT name, sql
|
||||
FROM __chai_catalog
|
||||
WHERE
|
||||
@@ -89,7 +89,7 @@ WHERE
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, b INTEGER, c INTEGER, CONSTRAINT test_a_b_c_unique UNIQUE (a DESC, b, c))"
|
||||
"sql": "CREATE TABLE test (a INTEGER NOT NULL, b INTEGER, c INTEGER, CONSTRAINT test_pk PRIMARY KEY (a), CONSTRAINT test_a_b_c_unique UNIQUE (a DESC, b, c))"
|
||||
}
|
||||
{
|
||||
"name": "test_a_b_c_idx",
|
||||
@@ -114,7 +114,7 @@ CREATE TABLE test(a INT UNIQUE, b INT, UNIQUE(a));
|
||||
-- error:
|
||||
|
||||
-- test: table constraint: different columns
|
||||
CREATE TABLE test(a INT UNIQUE, b INT, UNIQUE(b));
|
||||
CREATE TABLE test(a INT UNIQUE, b INT PRIMARY KEY, UNIQUE(b));
|
||||
SELECT name, sql
|
||||
FROM __chai_catalog
|
||||
WHERE
|
||||
@@ -124,7 +124,7 @@ WHERE
|
||||
/* result:
|
||||
{
|
||||
"name": "test",
|
||||
"sql": "CREATE TABLE test (a INTEGER, b INTEGER, CONSTRAINT test_a_unique UNIQUE (a), CONSTRAINT test_b_unique UNIQUE (b))"
|
||||
"sql": "CREATE TABLE test (a INTEGER, b INTEGER NOT NULL, CONSTRAINT test_a_unique UNIQUE (a), CONSTRAINT test_pk PRIMARY KEY (b), CONSTRAINT test_b_unique UNIQUE (b))"
|
||||
}
|
||||
{
|
||||
"name": "test_a_idx",
|
||||
|
@@ -4,7 +4,7 @@ on the result of the evaluation of the expression.
|
||||
*/
|
||||
|
||||
-- test: boolean check constraint
|
||||
CREATE TABLE test (a text CHECK(true));
|
||||
CREATE TABLE test (a text PRIMARY KEY CHECK(true));
|
||||
INSERT INTO test (a) VALUES ("hello");
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -14,7 +14,7 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: non-boolean check constraint, numeric result
|
||||
CREATE TABLE test (a text CHECK(1 + 1));
|
||||
CREATE TABLE test (a text PRIMARY KEY CHECK(1 + 1));
|
||||
INSERT INTO test (a) VALUES ("hello");
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -24,12 +24,12 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: non-boolean check constraint
|
||||
CREATE TABLE test (a text CHECK("hello"));
|
||||
CREATE TABLE test (a text PRIMARY KEY CHECK("hello"));
|
||||
INSERT INTO test (a) VALUES ("hello");
|
||||
-- error: row violates check constraint "test_check"
|
||||
|
||||
-- test: non-boolean check constraint, NULL
|
||||
CREATE TABLE test (a text CHECK(NULL));
|
||||
CREATE TABLE test (a text PRIMARY KEY CHECK(NULL));
|
||||
INSERT INTO test (a) VALUES ("hello");
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -44,7 +44,7 @@ on the type of the column
|
||||
*/
|
||||
|
||||
-- test: valid int
|
||||
CREATE TABLE test (a INT CHECK(a > 10));
|
||||
CREATE TABLE test (a INT PRIMARY KEY CHECK(a > 10));
|
||||
INSERT INTO test (a) VALUES (11);
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -54,22 +54,22 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: invalid int
|
||||
CREATE TABLE test (a INT CHECK(a > 10));
|
||||
CREATE TABLE test (a INT PRIMARY KEY CHECK(a > 10));
|
||||
INSERT INTO test (a) VALUES (1);
|
||||
-- error: row violates check constraint "test_check"
|
||||
|
||||
-- test: multiple checks, invalid int
|
||||
CREATE TABLE test (a INT CHECK(a > 10), CHECK(a < 20));
|
||||
CREATE TABLE test (a INT PRIMARY KEY CHECK(a > 10), CHECK(a < 20));
|
||||
INSERT INTO test (a) VALUES (40);
|
||||
-- error: row violates check constraint "test_check1"
|
||||
|
||||
-- test: text
|
||||
CREATE TABLE test (a INT CHECK(a > 10));
|
||||
CREATE TABLE test (a INT PRIMARY KEY CHECK(a > 10));
|
||||
INSERT INTO test (a) VALUES ("hello");
|
||||
-- error: cannot cast "hello" as integer: strconv.ParseInt: parsing "hello": invalid syntax
|
||||
|
||||
-- test: null
|
||||
CREATE TABLE test (a INT CHECK(a > 10), b int);
|
||||
CREATE TABLE test (a INT CHECK(a > 10), b int PRIMARY KEY);
|
||||
INSERT INTO test (b) VALUES (10);
|
||||
SELECT b FROM test;
|
||||
/* result:
|
||||
@@ -79,7 +79,7 @@ SELECT b FROM test;
|
||||
*/
|
||||
|
||||
-- test: double
|
||||
CREATE TABLE test (a int CHECK(a > 10));
|
||||
CREATE TABLE test (a int PRIMARY KEY CHECK(a > 10));
|
||||
INSERT INTO test (a) VALUES (15.2);
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- setup:
|
||||
CREATE TABLE foo(a INT, b INT, c INT, d INT, e INT);
|
||||
CREATE TABLE bar(a INT, b INT);
|
||||
CREATE TABLE foo(a INT PRIMARY KEY, b INT, c INT, d INT, e INT);
|
||||
CREATE TABLE bar(a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO bar (a, b) VALUES (1, 10);
|
||||
|
||||
-- test: same table
|
||||
@@ -47,14 +47,14 @@ SELECT * FROM foo;
|
||||
*/
|
||||
|
||||
-- test: With columns / Projection
|
||||
INSERT INTO foo (c, d) SELECT a, b FROM bar;
|
||||
INSERT INTO foo (a, c) SELECT b, a FROM bar;
|
||||
SELECT * FROM foo;
|
||||
/* result:
|
||||
{
|
||||
"a":null,
|
||||
"a":10,
|
||||
"b":null,
|
||||
"c":1,
|
||||
"d":10,
|
||||
"d":null,
|
||||
"e":null
|
||||
}
|
||||
*/
|
||||
|
@@ -17,7 +17,7 @@ INSERT INTO testpk (bar, foo) VALUES (1, 2);
|
||||
CREATE TABLE test_tc(
|
||||
b bool, db double,
|
||||
i bigint, bb blob, byt bytes,
|
||||
t text
|
||||
t text primary key
|
||||
);
|
||||
INSERT INTO test_tc (i, db, b, bb, byt, t) VALUES (10000000000, 21.21, true, "YmxvYlZhbHVlCg==", "Ynl0ZXNWYWx1ZQ==", "text");
|
||||
SELECT * FROM test_tc;
|
||||
@@ -33,7 +33,7 @@ SELECT * FROM test_tc;
|
||||
*/
|
||||
|
||||
-- test: insert with inferred constraints
|
||||
CREATE TABLE test_ic(a INTEGER, s.b TEXT);
|
||||
CREATE TABLE test_ic(a INTEGER PRIMARY KEY, s.b TEXT);
|
||||
INSERT INTO test_ic VALUES {s: 1};
|
||||
-- error:
|
||||
|
||||
@@ -49,10 +49,10 @@ SELECT * FROM test_oc;
|
||||
*/
|
||||
|
||||
-- test: insert with on conflict do nothing, unique
|
||||
CREATE TABLE test_oc(a INTEGER UNIQUE);
|
||||
INSERT INTO test_oc (a) VALUES (1) ON CONFLICT DO NOTHING;
|
||||
INSERT INTO test_oc (a) VALUES (1) ON CONFLICT DO NOTHING;
|
||||
SELECT * FROM test_oc;
|
||||
CREATE TABLE test_oc(pk INTEGER PRIMARY KEY, a INTEGER UNIQUE);
|
||||
INSERT INTO test_oc (pk, a) VALUES (1, 1) ON CONFLICT DO NOTHING;
|
||||
INSERT INTO test_oc (pk, a) VALUES (1, 1) ON CONFLICT DO NOTHING;
|
||||
SELECT a FROM test_oc;
|
||||
/* result:
|
||||
{
|
||||
a: 1
|
||||
@@ -60,7 +60,7 @@ SELECT * FROM test_oc;
|
||||
*/
|
||||
|
||||
-- test: insert with on conflict do nothing, unique with default
|
||||
CREATE TABLE test_oc(a INTEGER, b INTEGER UNIQUE DEFAULT 10);
|
||||
CREATE TABLE test_oc(a INTEGER PRIMARY KEY, b INTEGER UNIQUE DEFAULT 10);
|
||||
INSERT INTO test_oc (a) VALUES (1) ON CONFLICT DO NOTHING;
|
||||
INSERT INTO test_oc (a) VALUES (1) ON CONFLICT DO NOTHING;
|
||||
SELECT * FROM test_oc;
|
||||
@@ -107,7 +107,7 @@ SELECT * FROM test_oc;
|
||||
*/
|
||||
|
||||
-- test: insert with on conflict do replace, unique
|
||||
CREATE TABLE test_oc(a INTEGER UNIQUE, b INTEGER, c INTEGER);
|
||||
CREATE TABLE test_oc(a INTEGER UNIQUE, b INTEGER PRIMARY KEY, c INTEGER);
|
||||
INSERT INTO test_oc (a, b, c) VALUES (1, 1, 1);
|
||||
INSERT INTO test_oc (a, b, c) VALUES (1, 2, 3) ON CONFLICT DO REPLACE;
|
||||
SELECT * FROM test_oc;
|
||||
@@ -120,12 +120,12 @@ SELECT * FROM test_oc;
|
||||
*/
|
||||
|
||||
-- test: insert with on conflict do replace, not null
|
||||
CREATE TABLE test_oc(a INTEGER NOT NULL, b INTEGER, c INTEGER);
|
||||
CREATE TABLE test_oc(a INTEGER NOT NULL, b INTEGER PRIMARY KEY, c INTEGER);
|
||||
INSERT INTO test_oc (b, c) VALUES (1, 1) ON CONFLICT DO REPLACE;
|
||||
-- error:
|
||||
|
||||
-- test: insert with nextval
|
||||
CREATE TABLE test_oc(a INTEGER UNIQUE);
|
||||
CREATE TABLE test_oc(a INTEGER PRIMARY KEY);
|
||||
CREATE SEQUENCE test_seq;
|
||||
INSERT INTO test_oc (a) VALUES (nextval('test_seq'));
|
||||
INSERT INTO test_oc (a) VALUES (nextval('test_seq')), (nextval('test_seq'));
|
||||
@@ -143,25 +143,25 @@ SELECT * FROM test_oc;
|
||||
*/
|
||||
|
||||
-- test: duplicate column names: root
|
||||
CREATE TABLE test_df;
|
||||
CREATE TABLE test_df(a INT PRIMARY KEY);
|
||||
INSERT INTO test_df(a, a) VALUES (1, 10);
|
||||
-- error:
|
||||
|
||||
-- test: inserts must be silent
|
||||
CREATE TABLE test (a int);
|
||||
CREATE TABLE test (a int PRIMARY KEY);
|
||||
INSERT INTO test VALUES (1);
|
||||
/* result:
|
||||
*/
|
||||
|
||||
-- test: inserts must be silent: explain
|
||||
CREATE TABLE test (a int);
|
||||
CREATE TABLE test (a int PRIMARY KEY);
|
||||
EXPLAIN INSERT INTO test (a) VALUES (1);
|
||||
/* result:
|
||||
{plan: "rows.Emit((1)) | table.Validate(\"test\") | table.GenerateKey(\"test\") | table.Insert(\"test\") | discard()"}
|
||||
*/
|
||||
|
||||
-- test: with columns
|
||||
CREATE TABLE test(a int, b text);
|
||||
CREATE TABLE test(a int PRIMARY KEY, b text);
|
||||
INSERT INTO test(a, b) VALUES (1, 'a');
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
|
@@ -1,20 +1,20 @@
|
||||
-- test: enforced type
|
||||
CREATE TABLE test (a INT NOT NULL, b INT);
|
||||
CREATE TABLE test (a INT NOT NULL, b INT PRIMARY KEY);
|
||||
INSERT INTO test (b) VALUES (1);
|
||||
-- error:
|
||||
|
||||
-- test: non-enforced type
|
||||
CREATE TABLE test (a NOT NULL, b INT);
|
||||
CREATE TABLE test (a NOT NULL, b INT PRIMARY KEY);
|
||||
INSERT INTO test (b) VALUES (1);
|
||||
-- error:
|
||||
|
||||
-- test: with null
|
||||
CREATE TABLE test (a INT NOT NULL, b INT);
|
||||
CREATE TABLE test (a INT NOT NULL, b INT PRIMARY KEY);
|
||||
INSERT INTO test (a, b) VALUES (NULL, 1);
|
||||
-- error:
|
||||
|
||||
-- test: with missing column and default
|
||||
CREATE TABLE test (a INT NOT NULL DEFAULT 10, b INT);
|
||||
CREATE TABLE test (a INT NOT NULL DEFAULT 10, b INT PRIMARY KEY);
|
||||
INSERT INTO test (b) VALUES (1);
|
||||
SELECT a, b FROM test;
|
||||
/* result:
|
||||
@@ -25,6 +25,6 @@ SELECT a, b FROM test;
|
||||
*/
|
||||
|
||||
-- test: with null and default should fail
|
||||
CREATE TABLE test (a INT NOT NULL DEFAULT 10, b INT);
|
||||
CREATE TABLE test (a INT NOT NULL DEFAULT 10, b INT PRIMARY KEY);
|
||||
INSERT INTO test (a, b) VALUES (NULL, 1);
|
||||
-- error:
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- test: VALUES RETURNING *
|
||||
CREATE TABLE test (a INT, b INT);
|
||||
CREATE TABLE test (a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO test (a, b) VALUES (1, 2) RETURNING *;
|
||||
/* result:
|
||||
{
|
||||
@@ -9,7 +9,7 @@ INSERT INTO test (a, b) VALUES (1, 2) RETURNING *;
|
||||
*/
|
||||
|
||||
-- test: VALUES RETURNING with alias and explicit columns
|
||||
CREATE TABLE test (a INT, b INT);
|
||||
CREATE TABLE test (a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO test (a, b) VALUES (3, 4) RETURNING a, b as B;
|
||||
/* result:
|
||||
{
|
||||
@@ -19,9 +19,9 @@ INSERT INTO test (a, b) VALUES (3, 4) RETURNING a, b as B;
|
||||
*/
|
||||
|
||||
-- test: INSERT ... SELECT RETURNING a
|
||||
CREATE TABLE foo (c INT, d INT);
|
||||
CREATE TABLE foo (c INT PRIMARY KEY, d INT);
|
||||
INSERT INTO foo (c, d) VALUES (10, 20);
|
||||
CREATE TABLE test2 (a INT, b INT);
|
||||
CREATE TABLE test2 (a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO test2 (a, b) SELECT c, d FROM foo RETURNING a;
|
||||
/* result:
|
||||
{
|
||||
@@ -30,9 +30,9 @@ INSERT INTO test2 (a, b) SELECT c, d FROM foo RETURNING a;
|
||||
*/
|
||||
|
||||
-- test: INSERT ... SELECT RETURNING * with multiple rows
|
||||
CREATE TABLE foo2 (c INT, d INT);
|
||||
CREATE TABLE foo2 (c INT PRIMARY KEY, d INT);
|
||||
INSERT INTO foo2 (c, d) VALUES (1, 2), (3, 4);
|
||||
CREATE TABLE test3 (a INT, b INT);
|
||||
CREATE TABLE test3 (a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO test3 (a, b) SELECT c, d FROM foo2 RETURNING *;
|
||||
/* result:
|
||||
{ "a": 1, "b": 2 }
|
||||
|
@@ -1,26 +1,26 @@
|
||||
-- setup:
|
||||
CREATE TABLE test (a int unique, b int);
|
||||
CREATE TABLE test (pk int primary key, a int unique, b int);
|
||||
|
||||
-- test: same value
|
||||
INSERT INTO test (a, b) VALUES (1, 1);
|
||||
INSERT INTO test (a, b) VALUES (1, 1);
|
||||
INSERT INTO test (pk, a, b) VALUES (1, 1, 1);
|
||||
INSERT INTO test (pk, a, b) VALUES (2, 1, 1);
|
||||
-- error:
|
||||
|
||||
-- test: same value, same statement
|
||||
INSERT INTO test (a, b) VALUES (1, 1), (1, 1);
|
||||
INSERT INTO test (pk, a, b) VALUES (1, 1, 1), (2, 1, 1);
|
||||
-- error:
|
||||
|
||||
-- test: different values
|
||||
INSERT INTO test (a, b) VALUES (1, 1), (2, 2);
|
||||
SELECT * FROM test;
|
||||
INSERT INTO test (pk, a, b) VALUES (1, 1, 1), (2, 2, 2);
|
||||
SELECT a, b FROM test;
|
||||
/* result:
|
||||
{a: 1, b: 1}
|
||||
{a: 2, b: 2}
|
||||
*/
|
||||
|
||||
-- test: NULL
|
||||
INSERT INTO test (b) VALUES (1), (2);
|
||||
INSERT INTO test (a, b) VALUES (NULL, 3);
|
||||
INSERT INTO test (pk, b) VALUES (1, 1), (2, 2);
|
||||
INSERT INTO test (pk, a, b) VALUES (3, NULL, 3);
|
||||
SELECT a, b FROM test;
|
||||
/* result:
|
||||
{a: NULL, b: 1}
|
||||
|
@@ -1,31 +1,31 @@
|
||||
-- setup:
|
||||
CREATE TABLE test (a int, b int, c int, d int, UNIQUE (a, b, c));
|
||||
CREATE TABLE test (pk int primary key, a int, b int, c int, d int, UNIQUE (a, b, c));
|
||||
|
||||
-- test: same value
|
||||
INSERT INTO test (a, b, c, d) VALUES (1, 1, 1, 1);
|
||||
INSERT INTO test (a, b, c, d) VALUES (1, 1, 1, 1);
|
||||
INSERT INTO test (pk, a, b, c, d) VALUES (1, 1, 1, 1, 1);
|
||||
INSERT INTO test (pk, a, b, c, d) VALUES (2, 1, 1, 1, 1);
|
||||
-- error:
|
||||
|
||||
-- test: same value, same statement
|
||||
INSERT INTO test (a, b, c, d) VALUES (1, 1, 1, 1), (1, 1, 1, 1);
|
||||
INSERT INTO test (pk, a, b, c, d) VALUES (1, 1, 1, 1, 1), (2, 1, 1, 1, 1);
|
||||
-- error:
|
||||
|
||||
-- test: different values
|
||||
INSERT INTO test (a, b, c, d) VALUES (1, 1, 1, 1), (1, 2, 1, 1);
|
||||
SELECT * FROM test;
|
||||
INSERT INTO test (pk, a, b, c, d) VALUES (1, 1, 1, 1, 1), (2, 1, 2, 1, 1);
|
||||
SELECT a, b, c, d FROM test;
|
||||
/* result:
|
||||
{a: 1, b: 1, c: 1, d: 1}
|
||||
{a: 1, b: 2, c: 1, d: 1}
|
||||
*/
|
||||
|
||||
-- test: NULL
|
||||
INSERT INTO test (d) VALUES (1), (2);
|
||||
INSERT INTO test (c, d) VALUES (3, 3);
|
||||
INSERT INTO test (c, d) VALUES (3, 3);
|
||||
INSERT INTO test (b, c, d) VALUES (4, 4, 4);
|
||||
INSERT INTO test (b, c, d) VALUES (4, 4, 4);
|
||||
INSERT INTO test (a, b, c, d) VALUES (5, null, 5, 5);
|
||||
INSERT INTO test (a, c, d) VALUES (5, 5, 5);
|
||||
INSERT INTO test (pk, d) VALUES (1, 1), (2, 2);
|
||||
INSERT INTO test (pk, c, d) VALUES (3, 3, 3);
|
||||
INSERT INTO test (pk, c, d) VALUES (4, 3, 3);
|
||||
INSERT INTO test (pk, b, c, d) VALUES (5, 4, 4, 4);
|
||||
INSERT INTO test (pk, b, c, d) VALUES (6, 4, 4, 4);
|
||||
INSERT INTO test (pk, a, b, c, d) VALUES (7, 5, null, 5, 5);
|
||||
INSERT INTO test (pk, a, c, d) VALUES (8, 5, 5, 5);
|
||||
SELECT a, b, c, d FROM test;
|
||||
/* result:
|
||||
{a: NULL, b: NULL, c: NULL, d: 1}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- test: VALUES, with all columns
|
||||
CREATE TABLE test (a TEXT, b TEXT, c TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, b TEXT, c TEXT);
|
||||
INSERT INTO test (a, b, c) VALUES ('a', 'b', 'c');
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -11,7 +11,7 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: VALUES, with a few columns
|
||||
CREATE TABLE test (a TEXT, b TEXT, c TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, b TEXT, c TEXT);
|
||||
INSERT INTO test (b, a) VALUES ('b', 'a');
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -23,12 +23,12 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: VALUES, with too many columns
|
||||
CREATE TABLE test (a TEXT, b TEXT, c TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, b TEXT, c TEXT);
|
||||
INSERT INTO test (b, a, c, d) VALUES ('b', 'a', 'c', 'd');
|
||||
-- error: table has no column d
|
||||
|
||||
-- test: VALUES, no columns, all values
|
||||
CREATE TABLE test (a TEXT, b TEXT, c TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, b TEXT, c TEXT);
|
||||
INSERT INTO test VALUES ("a", 'b', 'c');
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -40,7 +40,7 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: VALUES, no columns, few values
|
||||
CREATE TABLE test (a TEXT, b TEXT, c TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, b TEXT, c TEXT);
|
||||
INSERT INTO test VALUES ('a', 'b');
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
@@ -52,17 +52,17 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: VALUES, ident
|
||||
CREATE TABLE test (a TEXT, b TEXT, c TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, b TEXT, c TEXT);
|
||||
INSERT INTO test (a) VALUES (a);
|
||||
-- error: no table specified
|
||||
|
||||
-- test: VALUES, ident string
|
||||
CREATE TABLE test (a TEXT, b TEXT, c TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, b TEXT, c TEXT);
|
||||
INSERT INTO test (a) VALUES (`a`);
|
||||
-- error: no table specified
|
||||
|
||||
-- test: VALUES, columns ident string
|
||||
CREATE TABLE test (a TEXT, `foo bar` TEXT);
|
||||
CREATE TABLE test (a TEXT PRIMARY KEY, `foo bar` TEXT);
|
||||
INSERT INTO test (a, `foo bar`) VALUES ('a', 'foo bar');
|
||||
SELECT * FROM test;
|
||||
/* result:
|
||||
|
@@ -1,12 +1,14 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(
|
||||
pk INT PRIMARY KEY,
|
||||
a TEXT,
|
||||
b INT,
|
||||
c BOOL,
|
||||
d DOUBLE
|
||||
);
|
||||
|
||||
INSERT INTO test (a, b, c, d) VALUES (
|
||||
INSERT INTO test (pk, a, b, c, d) VALUES (
|
||||
1,
|
||||
"FOO",
|
||||
42,
|
||||
true,
|
||||
|
@@ -1,9 +1,10 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(
|
||||
a TEXT
|
||||
pk INT PRIMARY KEY,
|
||||
a TEXT
|
||||
);
|
||||
|
||||
INSERT INTO test (a) VALUES (" hello "), ("!hello!"), (" !hello! ");
|
||||
INSERT INTO test (pk, a) VALUES (1, " hello "), (2, "!hello!"), (3, " !hello! ");
|
||||
|
||||
-- test: LTRIM TEXT default
|
||||
SELECT LTRIM(a) FROM test;
|
||||
|
@@ -1,9 +1,10 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(
|
||||
pk INT PRIMARY KEY,
|
||||
a TEXT
|
||||
);
|
||||
|
||||
INSERT INTO test (a) VALUES (" hello "), ("!hello!"), (" !hello! ");
|
||||
INSERT INTO test (pk, a) VALUES (1, " hello "), (2, "!hello!"), (3, " !hello! ");
|
||||
|
||||
-- test: RTRIM TEXT default
|
||||
SELECT RTRIM(a) FROM test;
|
||||
|
@@ -1,9 +1,10 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(
|
||||
pk INT PRIMARY KEY,
|
||||
a TEXT
|
||||
);
|
||||
|
||||
INSERT INTO test (a) VALUES (" hello "), ("!hello!"), (" !hello! ");
|
||||
INSERT INTO test (pk, a) VALUES (1, " hello "), (2, "!hello!"), (3, " !hello! ");
|
||||
|
||||
-- test: TRIM TEXT default
|
||||
SELECT TRIM(a) FROM test;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(
|
||||
a TEXT,
|
||||
a TEXT PRIMARY KEY,
|
||||
b INT,
|
||||
c BOOL,
|
||||
d DOUBLE
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a int);
|
||||
INSERT INTO test (a) VALUES (1), (2), (3), (4), (5);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a int);
|
||||
INSERT INTO test (pk, a) VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
|
||||
|
||||
-- test: GROUP BY a
|
||||
SELECT a FROM test GROUP BY a
|
||||
|
@@ -1,11 +1,11 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a INT, b TEXT, c bool);
|
||||
INSERT INTO test(a, b, c) VALUES
|
||||
(1, 'foo', true),
|
||||
(1, 'bar', false),
|
||||
(1, 'bar', NULL),
|
||||
(2, 'baz', NULL),
|
||||
(2, 'baz', NULL);
|
||||
CREATE TABLE test(pk INT PRIMARY KEY, a INT, b TEXT, c bool);
|
||||
INSERT INTO test(pk, a, b, c) VALUES
|
||||
(1, 1, 'foo', true),
|
||||
(2, 1, 'bar', false),
|
||||
(3, 1, 'bar', NULL),
|
||||
(4, 2, 'baz', NULL),
|
||||
(5, 2, 'baz', NULL);
|
||||
|
||||
-- test: literal
|
||||
SELECT DISTINCT 'a' FROM test;
|
||||
@@ -19,21 +19,31 @@ SELECT DISTINCT 'a' FROM test;
|
||||
SELECT DISTINCT * FROM test;
|
||||
/* result:
|
||||
{
|
||||
a: 1,
|
||||
b: "bar",
|
||||
c: null
|
||||
}
|
||||
{
|
||||
a: 1,
|
||||
b: "bar",
|
||||
c: false
|
||||
}
|
||||
{
|
||||
pk: 1,
|
||||
a: 1,
|
||||
b: "foo",
|
||||
c: true
|
||||
}
|
||||
{
|
||||
pk: 2,
|
||||
a: 1,
|
||||
b: "bar",
|
||||
c: false
|
||||
}
|
||||
{
|
||||
pk: 3,
|
||||
a: 1,
|
||||
b: "bar",
|
||||
c: null
|
||||
}
|
||||
{
|
||||
pk: 4,
|
||||
a: 2,
|
||||
b: "baz",
|
||||
c: null
|
||||
}
|
||||
{
|
||||
pk: 5,
|
||||
a: 2,
|
||||
b: "baz",
|
||||
c: null
|
||||
|
@@ -1,7 +1,7 @@
|
||||
-- test: one nullable column
|
||||
CREATE TABLE test (a INT);
|
||||
INSERT INTO test (a) VALUES (null), (null);
|
||||
SELECT * FROM test;
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a INT);
|
||||
INSERT INTO test (pk, a) VALUES (1, null), (2, null);
|
||||
SELECT a FROM test;
|
||||
/* result:
|
||||
{
|
||||
a: null
|
||||
@@ -12,9 +12,9 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: first column null
|
||||
CREATE TABLE test (a INT, b INT);
|
||||
INSERT INTO test (b) VALUES (1), (2);
|
||||
SELECT * FROM test;
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a INT, b INT);
|
||||
INSERT INTO test (pk, b) VALUES (1, 1), (2, 2);
|
||||
SELECT a, b FROM test;
|
||||
/* result:
|
||||
{
|
||||
a: null,
|
||||
@@ -27,9 +27,9 @@ SELECT * FROM test;
|
||||
*/
|
||||
|
||||
-- test: second column null
|
||||
CREATE TABLE test (a INT, b INT);
|
||||
INSERT INTO test (a) VALUES (1), (2);
|
||||
SELECT * FROM test;
|
||||
CREATE TABLE test (pk INT PRIMARY KEY, a INT, b INT);
|
||||
INSERT INTO test (pk, a) VALUES (1, 1), (2, 2);
|
||||
SELECT a, b FROM test;
|
||||
/* result:
|
||||
{
|
||||
a: 1,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a double, b double);
|
||||
CREATE TABLE test(a double, b double primary key);
|
||||
INSERT INTO test (a, b) VALUES (50, 3), (100, 4), (10, 2), (null, 1);
|
||||
|
||||
-- suite: no index
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a INT, b DOUBLE);
|
||||
CREATE TABLE test(a INT, b DOUBLE PRIMARY KEY);
|
||||
CREATE INDEX on test(a DESC, b DESC);
|
||||
INSERT INTO test (a, b) VALUES (50, 2), (100, 3), (10, 1), (100, 4);
|
||||
|
||||
@@ -78,7 +78,7 @@ SELECT a, b FROM test ORDER BY b DESC;
|
||||
EXPLAIN SELECT a, b FROM test ORDER BY b DESC;
|
||||
/* result:
|
||||
{
|
||||
plan: "table.Scan(\"test\") | rows.Project(a, b) | rows.TempTreeSortReverse(b)"
|
||||
plan: "table.ScanReverse(\"test\") | rows.Project(a, b)"
|
||||
}
|
||||
*/
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a timestamp);
|
||||
INSERT INTO test (a) VALUES ("2023"), ("2025"), ("2021"), ("2000");
|
||||
CREATE TABLE test(pk int primary key, a timestamp );
|
||||
INSERT INTO test VALUES (1, "2023"), (2, "2025"), (3, "2021"), (4, "2000");
|
||||
|
||||
-- suite: no index
|
||||
|
||||
@@ -28,15 +28,19 @@ SELECT a FROM test ORDER BY a;
|
||||
SELECT * FROM test ORDER BY a;
|
||||
/* result:
|
||||
{
|
||||
pk: 4,
|
||||
a: "2000-01-01T00:00:00Z",
|
||||
}
|
||||
{
|
||||
pk: 3,
|
||||
a: "2021-01-01T00:00:00Z"
|
||||
}
|
||||
{
|
||||
pk: 1,
|
||||
a: "2023-01-01T00:00:00Z"
|
||||
}
|
||||
{
|
||||
pk: 2,
|
||||
a: "2025-01-01T00:00:00Z"
|
||||
}
|
||||
*/
|
||||
@@ -62,15 +66,19 @@ SELECT a FROM test ORDER BY a DESC;
|
||||
SELECT * FROM test ORDER BY a DESC;
|
||||
/* result:
|
||||
{
|
||||
pk: 2,
|
||||
a: "2025-01-01T00:00:00Z",
|
||||
}
|
||||
{
|
||||
pk: 1,
|
||||
a: "2023-01-01T00:00:00Z"
|
||||
}
|
||||
{
|
||||
pk: 3,
|
||||
a: "2021-01-01T00:00:00Z"
|
||||
}
|
||||
{
|
||||
pk: 4,
|
||||
a: "2000-01-01T00:00:00Z"
|
||||
}
|
||||
*/
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a double, b int, c bool);
|
||||
CREATE TABLE test(a double primary key, b int, c bool);
|
||||
INSERT INTO test(a, b, c) VALUES (1, 1, true);
|
||||
|
||||
-- suite: no index
|
||||
|
@@ -1,7 +1,7 @@
|
||||
-- setup:
|
||||
CREATE TABLE foo(a DOUBLE, b DOUBLE);
|
||||
CREATE TABLE bar(a DOUBLE, b DOUBLE);
|
||||
CREATE TABLE baz(x TEXT, y TEXT);
|
||||
CREATE TABLE foo(a DOUBLE PRIMARY KEY, b DOUBLE);
|
||||
CREATE TABLE bar(a DOUBLE PRIMARY KEY, b DOUBLE);
|
||||
CREATE TABLE baz(x TEXT PRIMARY KEY, y TEXT);
|
||||
INSERT INTO foo (a,b) VALUES (1.0, 1.0), (2.0, 2.0);
|
||||
INSERT INTO bar (a,b) VALUES (2.0, 2.0), (3.0, 3.0);
|
||||
INSERT INTO baz (x,y) VALUES ("a", "a"), ("b", "b");
|
||||
|
@@ -1 +0,0 @@
|
||||
-- TODO
|
@@ -1,8 +1,8 @@
|
||||
-- test: int type constraint, double
|
||||
CREATE TABLE test (a int CHECK(a > 10));
|
||||
INSERT INTO test (a) VALUES (11);
|
||||
CREATE TABLE test (pk int primary key, a int CHECK(a > 10));
|
||||
INSERT INTO test (pk, a) VALUES (11, 11);
|
||||
UPDATE test SET a = 15.2;
|
||||
SELECT * FROM test;
|
||||
SELECT a FROM test;
|
||||
/* result:
|
||||
{
|
||||
a: 15
|
||||
|
@@ -1,7 +1,7 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a int UNIQUE);
|
||||
CREATE TABLE test(pk int primary key, a int UNIQUE);
|
||||
|
||||
-- test: conflict
|
||||
INSERT INTO test VALUES (1), (2);
|
||||
INSERT INTO test VALUES (1, 1), (2, 2);
|
||||
UPDATE test SET a = 2 WHERE a = 1;
|
||||
-- error: UNIQUE constraint error: [a]
|
@@ -1,5 +1,5 @@
|
||||
-- test: BETWEEN with index
|
||||
CREATE TABLE test(a int UNIQUE);
|
||||
CREATE TABLE test(pk int primary key, a int UNIQUE);
|
||||
EXPLAIN SELECT * FROM test WHERE a BETWEEN 1 AND 2;
|
||||
/* result:
|
||||
{
|
||||
@@ -8,7 +8,7 @@ EXPLAIN SELECT * FROM test WHERE a BETWEEN 1 AND 2;
|
||||
*/
|
||||
|
||||
-- test: BETWEEN with composite index: 2 BETWEENs
|
||||
CREATE TABLE test(a int, b int, c int);
|
||||
CREATE TABLE test(pk int primary key, a int, b int, c int);
|
||||
CREATE INDEX on test(a, b);
|
||||
EXPLAIN SELECT * FROM test WHERE a BETWEEN 1 AND 2 AND b BETWEEN 3 AND 4;
|
||||
/* result:
|
||||
@@ -18,7 +18,7 @@ EXPLAIN SELECT * FROM test WHERE a BETWEEN 1 AND 2 AND b BETWEEN 3 AND 4;
|
||||
*/
|
||||
|
||||
-- test: BETWEEN with composite index: one BETWEEN at the end
|
||||
CREATE TABLE test(a int, b int, c int, d int, e int);
|
||||
CREATE TABLE test(pk int primary key, a int, b int, c int, d int, e int);
|
||||
CREATE INDEX on test(a, b, c, d);
|
||||
EXPLAIN SELECT * FROM test WHERE a = 1 AND b = 10 AND c = 100 AND d BETWEEN 1000 AND 2000 AND e > 10000;
|
||||
/* result:
|
||||
|
@@ -1,18 +1,18 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a int, b int, c int);
|
||||
CREATE TABLE test(pk int primary key, a int, b int, c int);
|
||||
|
||||
CREATE INDEX test_a ON test(a);
|
||||
|
||||
CREATE INDEX test_b ON test(b);
|
||||
|
||||
INSERT INTO
|
||||
test (a, b, c)
|
||||
test (pk, a, b, c)
|
||||
VALUES
|
||||
(1, 1, 1),
|
||||
(2, 2, 2),
|
||||
(3, 3, 3),
|
||||
(4, 4, 4),
|
||||
(5, 5, 5);
|
||||
(1, 1, 1, 1),
|
||||
(2, 2, 2, 2),
|
||||
(3, 3, 3, 3),
|
||||
(4, 4, 4, 4),
|
||||
(5, 5, 5, 5);
|
||||
|
||||
-- test: non-indexed column path, ASC
|
||||
EXPLAIN SELECT * FROM test ORDER BY c;
|
||||
|
@@ -1,16 +1,16 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a int, b int, c int);
|
||||
CREATE TABLE test(pk int primary key, a int, b int, c int);
|
||||
|
||||
CREATE INDEX test_a_b ON test(a, b);
|
||||
|
||||
INSERT INTO
|
||||
test (a, b, c)
|
||||
test (pk, a, b, c)
|
||||
VALUES
|
||||
(1, 1, 1),
|
||||
(2, 2, 2),
|
||||
(3, 3, 3),
|
||||
(4, 4, 4),
|
||||
(5, 5, 5);
|
||||
(1, 1, 1, 1),
|
||||
(2, 2, 2, 2),
|
||||
(3, 3, 3, 3),
|
||||
(4, 4, 4, 4),
|
||||
(5, 5, 5, 5);
|
||||
|
||||
-- test: non-indexed column path, ASC
|
||||
EXPLAIN SELECT * FROM test ORDER BY c;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
-- setup:
|
||||
CREATE table test(a int);
|
||||
CREATE table test(pk int primary key, a int);
|
||||
|
||||
-- test: precalculate constant
|
||||
EXPLAIN SELECT * FROM test WHERE 3 + 4 > a + 3 % 2;
|
||||
|
@@ -1,18 +1,18 @@
|
||||
-- setup:
|
||||
CREATE TABLE test(a int, b int, c int);
|
||||
CREATE TABLE test(pk int primary key, a int, b int, c int);
|
||||
|
||||
CREATE INDEX test_a ON test(a);
|
||||
|
||||
CREATE INDEX test_b ON test(b);
|
||||
|
||||
INSERT INTO
|
||||
test (a, b, c)
|
||||
test (pk, a, b, c)
|
||||
VALUES
|
||||
(1, 1, 1),
|
||||
(2, 2, 2),
|
||||
(3, 3, 3),
|
||||
(4, 4, 4),
|
||||
(5, 5, 5);
|
||||
(1, 1, 1, 1),
|
||||
(2, 2, 2, 2),
|
||||
(3, 3, 3, 3),
|
||||
(4, 4, 4, 4),
|
||||
(5, 5, 5, 5);
|
||||
|
||||
-- test: =
|
||||
EXPLAIN SELECT * FROM test WHERE a = 10 AND b = 5;
|
||||
|
Reference in New Issue
Block a user