remove rowid

This commit is contained in:
Asdine El Hrychy
2025-09-07 23:24:53 +08:00
parent ab8a0d4cf9
commit 613ca304f4
85 changed files with 636 additions and 658 deletions

View File

@@ -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")

View File

@@ -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');

View File

@@ -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)

View File

@@ -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)
}
}
}

View File

@@ -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)
}

View File

@@ -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=

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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.

View File

@@ -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;

View File

@@ -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);
`)

View File

@@ -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

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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;
`)

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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})

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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);
`,
)

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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()
}

View File

@@ -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...)

View File

@@ -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()
}

View File

@@ -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)

View File

@@ -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()
}

View File

@@ -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})

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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:

View File

@@ -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);

View File

@@ -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:

View File

@@ -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))"
}
*/

View File

@@ -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))"
}
*/

View File

@@ -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))"
}
*/

View File

@@ -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))"
}
*/

View File

@@ -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:

View File

@@ -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))"
}
*/

View File

@@ -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",

View File

@@ -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:

View File

@@ -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
}
*/

View File

@@ -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:

View File

@@ -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:

View File

@@ -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 }

View File

@@ -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}

View File

@@ -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}

View File

@@ -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:

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,6 +1,6 @@
-- setup:
CREATE TABLE test(
a TEXT,
a TEXT PRIMARY KEY,
b INT,
c BOOL,
d DOUBLE

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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)"
}
*/

View File

@@ -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"
}
*/

View File

@@ -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

View File

@@ -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");

View File

@@ -1 +0,0 @@
-- TODO

View File

@@ -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

View File

@@ -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]

View File

@@ -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:

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;