diff --git a/cmd/chai/dbutil/dump_test.go b/cmd/chai/dbutil/dump_test.go index 88f4f592..a5a957c1 100644 --- a/cmd/chai/dbutil/dump_test.go +++ b/cmd/chai/dbutil/dump_test.go @@ -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") diff --git a/cmd/chai/dbutil/exec_test.go b/cmd/chai/dbutil/exec_test.go index 8bb34675..b810b08f 100644 --- a/cmd/chai/dbutil/exec_test.go +++ b/cmd/chai/dbutil/exec_test.go @@ -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'); diff --git a/cmd/chai/shell/command_test.go b/cmd/chai/shell/command_test.go index 689a09d3..a459b5aa 100644 --- a/cmd/chai/shell/command_test.go +++ b/cmd/chai/shell/command_test.go @@ -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) diff --git a/db_test.go b/db_test.go index aa38ba58..65a2c173 100644 --- a/db_test.go +++ b/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) + } + } +} diff --git a/example_test.go b/example_test.go index 2669039e..31f90076 100644 --- a/example_test.go +++ b/example_test.go @@ -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) } diff --git a/go.work.sum b/go.work.sum index bbffd7ff..33092ed5 100644 --- a/go.work.sum +++ b/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= diff --git a/internal/database/catalog.go b/internal/database/catalog.go index 97bfcd2d..388c7b65 100644 --- a/internal/database/catalog.go +++ b/internal/database/catalog.go @@ -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 } diff --git a/internal/database/catalog_test.go b/internal/database/catalog_test.go index 45e5ab6f..47e718c3 100644 --- a/internal/database/catalog_test.go +++ b/internal/database/catalog_test.go @@ -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) } diff --git a/internal/database/catalogstore/store.go b/internal/database/catalogstore/store.go index 9546fb59..33ad1ab0 100644 --- a/internal/database/catalogstore/store.go +++ b/internal/database/catalogstore/store.go @@ -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 diff --git a/internal/database/constraint.go b/internal/database/constraint.go index 7edfe98d..624d1f82 100644 --- a/internal/database/constraint.go +++ b/internal/database/constraint.go @@ -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 diff --git a/internal/database/info.go b/internal/database/info.go index a4093c90..e829a36d 100644 --- a/internal/database/info.go +++ b/internal/database/info.go @@ -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 diff --git a/internal/database/table.go b/internal/database/table.go index 33ded131..c70ed154 100644 --- a/internal/database/table.go +++ b/internal/database/table.go @@ -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 } diff --git a/internal/database/table_test.go b/internal/database/table_test.go index 23fd018b..3984e484 100644 --- a/internal/database/table_test.go +++ b/internal/database/table_test.go @@ -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. diff --git a/internal/kv/session_test.go b/internal/kv/session_test.go index 5b3abf6f..de4cff31 100644 --- a/internal/kv/session_test.go +++ b/internal/kv/session_test.go @@ -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; diff --git a/internal/planner/optimizer_test.go b/internal/planner/optimizer_test.go index 45995768..db20bc99 100644 --- a/internal/planner/optimizer_test.go +++ b/internal/planner/optimizer_test.go @@ -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); `) diff --git a/internal/query/statement/alter_test.go b/internal/query/statement/alter_test.go index 28c3ae70..159927bd 100644 --- a/internal/query/statement/alter_test.go +++ b/internal/query/statement/alter_test.go @@ -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 diff --git a/internal/query/statement/create.go b/internal/query/statement/create.go index 2c0140e2..d6c396a3 100644 --- a/internal/query/statement/create.go +++ b/internal/query/statement/create.go @@ -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) diff --git a/internal/query/statement/create_test.go b/internal/query/statement/create_test.go index 45ed889b..864a6ec0 100644 --- a/internal/query/statement/create_test.go +++ b/internal/query/statement/create_test.go @@ -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 { diff --git a/internal/query/statement/drop.go b/internal/query/statement/drop.go index ac9d7f38..90a376a5 100644 --- a/internal/query/statement/drop.go +++ b/internal/query/statement/drop.go @@ -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 } diff --git a/internal/query/statement/drop_test.go b/internal/query/statement/drop_test.go index 4d1f6f2b..610c9656 100644 --- a/internal/query/statement/drop_test.go +++ b/internal/query/statement/drop_test.go @@ -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; `) diff --git a/internal/query/statement/insert_test.go b/internal/query/statement/insert_test.go index f7fa61fd..086f2124 100644 --- a/internal/query/statement/insert_test.go +++ b/internal/query/statement/insert_test.go @@ -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) diff --git a/internal/query/statement/reindex_test.go b/internal/query/statement/reindex_test.go index e547f6a2..3d3834af 100644 --- a/internal/query/statement/reindex_test.go +++ b/internal/query/statement/reindex_test.go @@ -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); diff --git a/internal/query/statement/select_test.go b/internal/query/statement/select_test.go index 400f55f5..42e6ad7d 100644 --- a/internal/query/statement/select_test.go +++ b/internal/query/statement/select_test.go @@ -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) diff --git a/internal/query/statement/update_test.go b/internal/query/statement/update_test.go index 04bc90d7..270afe00 100644 --- a/internal/query/statement/update_test.go +++ b/internal/query/statement/update_test.go @@ -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) diff --git a/internal/sql/driver/driver_test.go b/internal/sql/driver/driver_test.go index 77fd6cf4..8e1dcfeb 100644 --- a/internal/sql/driver/driver_test.go +++ b/internal/sql/driver/driver_test.go @@ -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}) diff --git a/internal/sql/parser/delete_test.go b/internal/sql/parser/delete_test.go index 23601a2a..adaf9545 100644 --- a/internal/sql/parser/delete_test.go +++ b/internal/sql/parser/delete_test.go @@ -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) diff --git a/internal/sql/parser/insert.go b/internal/sql/parser/insert.go index d50e664e..905a2270 100644 --- a/internal/sql/parser/insert.go +++ b/internal/sql/parser/insert.go @@ -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 { diff --git a/internal/sql/parser/insert_test.go b/internal/sql/parser/insert_test.go index b344332c..9e358b02 100644 --- a/internal/sql/parser/insert_test.go +++ b/internal/sql/parser/insert_test.go @@ -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 { diff --git a/internal/sql/parser/select_test.go b/internal/sql/parser/select_test.go index 5a0d6ed4..d4a46abd 100644 --- a/internal/sql/parser/select_test.go +++ b/internal/sql/parser/select_test.go @@ -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); `, ) diff --git a/internal/sql/parser/update_test.go b/internal/sql/parser/update_test.go index 1434059a..f5817b67 100644 --- a/internal/sql/parser/update_test.go +++ b/internal/sql/parser/update_test.go @@ -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) diff --git a/internal/stream/index/delete.go b/internal/stream/index/delete.go index 63b7dbb7..1d3b0d36 100644 --- a/internal/stream/index/delete.go +++ b/internal/stream/index/delete.go @@ -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 { diff --git a/internal/stream/index/insert.go b/internal/stream/index/insert.go index a0a78565..a558385a 100644 --- a/internal/stream/index/insert.go +++ b/internal/stream/index/insert.go @@ -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() } diff --git a/internal/stream/index/scan_test.go b/internal/stream/index/scan_test.go index 6bc667f3..39b794f6 100644 --- a/internal/stream/index/scan_test.go +++ b/internal/stream/index/scan_test.go @@ -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...) diff --git a/internal/stream/index/validate.go b/internal/stream/index/validate.go index f4f3c1c9..d6afb1b2 100644 --- a/internal/stream/index/validate.go +++ b/internal/stream/index/validate.go @@ -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() } diff --git a/internal/stream/operator_test.go b/internal/stream/operator_test.go index de9eff01..0636d622 100644 --- a/internal/stream/operator_test.go +++ b/internal/stream/operator_test.go @@ -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) diff --git a/internal/stream/rows/group_aggregate.go b/internal/stream/rows/group_aggregate.go index 24102229..728ecc3e 100644 --- a/internal/stream/rows/group_aggregate.go +++ b/internal/stream/rows/group_aggregate.go @@ -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() } diff --git a/internal/stream/rows/group_aggregate_test.go b/internal/stream/rows/group_aggregate_test.go index a91e5704..97d500bb 100644 --- a/internal/stream/rows/group_aggregate_test.go +++ b/internal/stream/rows/group_aggregate_test.go @@ -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}) diff --git a/internal/stream/rows/project.go b/internal/stream/rows/project.go index 835b67dc..4829be37 100644 --- a/internal/stream/rows/project.go +++ b/internal/stream/rows/project.go @@ -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) { diff --git a/internal/stream/rows/temp_tree_sort.go b/internal/stream/rows/temp_tree_sort.go index 9c19635a..63d0cc4e 100644 --- a/internal/stream/rows/temp_tree_sort.go +++ b/internal/stream/rows/temp_tree_sort.go @@ -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) { diff --git a/internal/stream/rows/temp_tree_sort_test.go b/internal/stream/rows/temp_tree_sort_test.go index da18c19d..23f8cba9 100644 --- a/internal/stream/rows/temp_tree_sort_test.go +++ b/internal/stream/rows/temp_tree_sort_test.go @@ -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 } diff --git a/internal/stream/table/delete.go b/internal/stream/table/delete.go index 8346789e..59eb7a15 100644 --- a/internal/stream/table/delete.go +++ b/internal/stream/table/delete.go @@ -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 { diff --git a/internal/stream/table/insert.go b/internal/stream/table/insert.go index beaa7c3d..e9a8925c 100644 --- a/internal/stream/table/insert.go +++ b/internal/stream/table/insert.go @@ -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 { diff --git a/internal/stream/table/key.go b/internal/stream/table/key.go index bd098ddf..9b91d4ab 100644 --- a/internal/stream/table/key.go +++ b/internal/stream/table/key.go @@ -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 { diff --git a/internal/stream/table/replace.go b/internal/stream/table/replace.go index 6c56ff45..941cb040 100644 --- a/internal/stream/table/replace.go +++ b/internal/stream/table/replace.go @@ -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 { diff --git a/internal/stream/table/validate.go b/internal/stream/table/validate.go index 13b54ab9..acd08af9 100644 --- a/internal/stream/table/validate.go +++ b/internal/stream/table/validate.go @@ -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 { diff --git a/sqltests/ALTER_TABLE/add_column.sql b/sqltests/ALTER_TABLE/add_column.sql index dba21422..86bb197a 100644 --- a/sqltests/ALTER_TABLE/add_column.sql +++ b/sqltests/ALTER_TABLE/add_column.sql @@ -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); diff --git a/sqltests/ALTER_TABLE/rename.sql b/sqltests/ALTER_TABLE/rename.sql index 676e0b3e..b71b8457 100644 --- a/sqltests/ALTER_TABLE/rename.sql +++ b/sqltests/ALTER_TABLE/rename.sql @@ -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: diff --git a/sqltests/CREATE_INDEX/base.sql b/sqltests/CREATE_INDEX/base.sql index dcff339d..a643235b 100644 --- a/sqltests/CREATE_INDEX/base.sql +++ b/sqltests/CREATE_INDEX/base.sql @@ -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); diff --git a/sqltests/CREATE_INDEX/undeclared.sql b/sqltests/CREATE_INDEX/undeclared.sql index 4cda4b79..e5669b7e 100644 --- a/sqltests/CREATE_INDEX/undeclared.sql +++ b/sqltests/CREATE_INDEX/undeclared.sql @@ -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: diff --git a/sqltests/CREATE_TABLE/base.sql b/sqltests/CREATE_TABLE/base.sql index ee3b3809..49c2ed4c 100644 --- a/sqltests/CREATE_TABLE/base.sql +++ b/sqltests/CREATE_TABLE/base.sql @@ -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))" } */ diff --git a/sqltests/CREATE_TABLE/check.sql b/sqltests/CREATE_TABLE/check.sql index e086a3c5..3456ed7c 100644 --- a/sqltests/CREATE_TABLE/check.sql +++ b/sqltests/CREATE_TABLE/check.sql @@ -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))" } */ diff --git a/sqltests/CREATE_TABLE/constraints.sql b/sqltests/CREATE_TABLE/constraints.sql index c671859d..737c300e 100644 --- a/sqltests/CREATE_TABLE/constraints.sql +++ b/sqltests/CREATE_TABLE/constraints.sql @@ -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))" } */ diff --git a/sqltests/CREATE_TABLE/default.sql b/sqltests/CREATE_TABLE/default.sql index 864768ce..3236e669 100644 --- a/sqltests/CREATE_TABLE/default.sql +++ b/sqltests/CREATE_TABLE/default.sql @@ -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))" } */ diff --git a/sqltests/CREATE_TABLE/not_null.sql b/sqltests/CREATE_TABLE/not_null.sql index b94efa21..bbf8d227 100644 --- a/sqltests/CREATE_TABLE/not_null.sql +++ b/sqltests/CREATE_TABLE/not_null.sql @@ -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: diff --git a/sqltests/CREATE_TABLE/types.sql b/sqltests/CREATE_TABLE/types.sql index 6410e311..92f1ef03 100644 --- a/sqltests/CREATE_TABLE/types.sql +++ b/sqltests/CREATE_TABLE/types.sql @@ -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))" } */ diff --git a/sqltests/CREATE_TABLE/unique.sql b/sqltests/CREATE_TABLE/unique.sql index e964a24b..1766c2ad 100644 --- a/sqltests/CREATE_TABLE/unique.sql +++ b/sqltests/CREATE_TABLE/unique.sql @@ -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", diff --git a/sqltests/INSERT/check.sql b/sqltests/INSERT/check.sql index a19f75ad..a561edf4 100644 --- a/sqltests/INSERT/check.sql +++ b/sqltests/INSERT/check.sql @@ -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: diff --git a/sqltests/INSERT/insert_select.sql b/sqltests/INSERT/insert_select.sql index 3c3630b8..7c839b15 100644 --- a/sqltests/INSERT/insert_select.sql +++ b/sqltests/INSERT/insert_select.sql @@ -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 } */ diff --git a/sqltests/INSERT/misc.sql b/sqltests/INSERT/misc.sql index 3aaa70d1..5fa63b60 100644 --- a/sqltests/INSERT/misc.sql +++ b/sqltests/INSERT/misc.sql @@ -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: diff --git a/sqltests/INSERT/not_null.sql b/sqltests/INSERT/not_null.sql index c8cbad47..17f910d4 100644 --- a/sqltests/INSERT/not_null.sql +++ b/sqltests/INSERT/not_null.sql @@ -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: diff --git a/sqltests/INSERT/returning.sql b/sqltests/INSERT/returning.sql index bd7ba80f..69149e5d 100644 --- a/sqltests/INSERT/returning.sql +++ b/sqltests/INSERT/returning.sql @@ -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 } diff --git a/sqltests/INSERT/unique.sql b/sqltests/INSERT/unique.sql index ec199fa2..f5d8e72f 100644 --- a/sqltests/INSERT/unique.sql +++ b/sqltests/INSERT/unique.sql @@ -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} diff --git a/sqltests/INSERT/unique_composite.sql b/sqltests/INSERT/unique_composite.sql index 5ded1056..ffeaa49e 100644 --- a/sqltests/INSERT/unique_composite.sql +++ b/sqltests/INSERT/unique_composite.sql @@ -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} diff --git a/sqltests/INSERT/values.sql b/sqltests/INSERT/values.sql index 03f9ba20..c4fad7fa 100644 --- a/sqltests/INSERT/values.sql +++ b/sqltests/INSERT/values.sql @@ -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: diff --git a/sqltests/SELECT/STRINGS/lower.sql b/sqltests/SELECT/STRINGS/lower.sql index f748bf61..fa35b5a1 100644 --- a/sqltests/SELECT/STRINGS/lower.sql +++ b/sqltests/SELECT/STRINGS/lower.sql @@ -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, diff --git a/sqltests/SELECT/STRINGS/ltrim.sql b/sqltests/SELECT/STRINGS/ltrim.sql index c52fb1d2..5f1026a9 100644 --- a/sqltests/SELECT/STRINGS/ltrim.sql +++ b/sqltests/SELECT/STRINGS/ltrim.sql @@ -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; diff --git a/sqltests/SELECT/STRINGS/rtrim.sql b/sqltests/SELECT/STRINGS/rtrim.sql index a54acb6e..2da5b8f8 100644 --- a/sqltests/SELECT/STRINGS/rtrim.sql +++ b/sqltests/SELECT/STRINGS/rtrim.sql @@ -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; diff --git a/sqltests/SELECT/STRINGS/trim.sql b/sqltests/SELECT/STRINGS/trim.sql index ca0254d0..611c001b 100644 --- a/sqltests/SELECT/STRINGS/trim.sql +++ b/sqltests/SELECT/STRINGS/trim.sql @@ -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; diff --git a/sqltests/SELECT/STRINGS/upper.sql b/sqltests/SELECT/STRINGS/upper.sql index 3b3d84ce..27c07220 100644 --- a/sqltests/SELECT/STRINGS/upper.sql +++ b/sqltests/SELECT/STRINGS/upper.sql @@ -1,6 +1,6 @@ -- setup: CREATE TABLE test( - a TEXT, + a TEXT PRIMARY KEY, b INT, c BOOL, d DOUBLE diff --git a/sqltests/SELECT/aggregation.sql b/sqltests/SELECT/aggregation.sql index fe6ffc2c..01919882 100644 --- a/sqltests/SELECT/aggregation.sql +++ b/sqltests/SELECT/aggregation.sql @@ -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 diff --git a/sqltests/SELECT/distinct.sql b/sqltests/SELECT/distinct.sql index 987e91cc..3bfb8cf0 100644 --- a/sqltests/SELECT/distinct.sql +++ b/sqltests/SELECT/distinct.sql @@ -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 diff --git a/sqltests/SELECT/nullable.sql b/sqltests/SELECT/nullable.sql index c70c75ef..ec7d9b2a 100644 --- a/sqltests/SELECT/nullable.sql +++ b/sqltests/SELECT/nullable.sql @@ -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, diff --git a/sqltests/SELECT/order_by.sql b/sqltests/SELECT/order_by.sql index e15d7bad..6db5496a 100644 --- a/sqltests/SELECT/order_by.sql +++ b/sqltests/SELECT/order_by.sql @@ -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 diff --git a/sqltests/SELECT/order_by_desc_index.sql b/sqltests/SELECT/order_by_desc_index.sql index e27c50fc..4effac3d 100644 --- a/sqltests/SELECT/order_by_desc_index.sql +++ b/sqltests/SELECT/order_by_desc_index.sql @@ -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)" } */ diff --git a/sqltests/SELECT/order_by_timestamp.sql b/sqltests/SELECT/order_by_timestamp.sql index 86f8f717..cd176cbd 100644 --- a/sqltests/SELECT/order_by_timestamp.sql +++ b/sqltests/SELECT/order_by_timestamp.sql @@ -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" } */ diff --git a/sqltests/SELECT/projection_table.sql b/sqltests/SELECT/projection_table.sql index 0eaad22c..7a77e108 100644 --- a/sqltests/SELECT/projection_table.sql +++ b/sqltests/SELECT/projection_table.sql @@ -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 diff --git a/sqltests/SELECT/union.sql b/sqltests/SELECT/union.sql index 19829b65..57fb3bc7 100644 --- a/sqltests/SELECT/union.sql +++ b/sqltests/SELECT/union.sql @@ -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"); diff --git a/sqltests/UPDATE/base.sql b/sqltests/UPDATE/base.sql deleted file mode 100644 index af3b9497..00000000 --- a/sqltests/UPDATE/base.sql +++ /dev/null @@ -1 +0,0 @@ --- TODO \ No newline at end of file diff --git a/sqltests/UPDATE/check.sql b/sqltests/UPDATE/check.sql index bb2c7e95..844e7555 100644 --- a/sqltests/UPDATE/check.sql +++ b/sqltests/UPDATE/check.sql @@ -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 diff --git a/sqltests/UPDATE/unique.sql b/sqltests/UPDATE/unique.sql index b29715bf..37ff0339 100644 --- a/sqltests/UPDATE/unique.sql +++ b/sqltests/UPDATE/unique.sql @@ -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] \ No newline at end of file diff --git a/sqltests/planning/between.sql b/sqltests/planning/between.sql index d154c07c..714e1bda 100644 --- a/sqltests/planning/between.sql +++ b/sqltests/planning/between.sql @@ -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: diff --git a/sqltests/planning/order_by.sql b/sqltests/planning/order_by.sql index 8fd4c9b5..ebfe613c 100644 --- a/sqltests/planning/order_by.sql +++ b/sqltests/planning/order_by.sql @@ -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; diff --git a/sqltests/planning/order_by_composite.sql b/sqltests/planning/order_by_composite.sql index 0bb84fe2..262c24e8 100644 --- a/sqltests/planning/order_by_composite.sql +++ b/sqltests/planning/order_by_composite.sql @@ -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; diff --git a/sqltests/planning/precalculate.sql b/sqltests/planning/precalculate.sql index da93735d..aba52b66 100644 --- a/sqltests/planning/precalculate.sql +++ b/sqltests/planning/precalculate.sql @@ -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; diff --git a/sqltests/planning/where.sql b/sqltests/planning/where.sql index 2c71e881..35a213e4 100644 --- a/sqltests/planning/where.sql +++ b/sqltests/planning/where.sql @@ -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;