From 41e2bac5e2f1c4bfa41ea47454a08f0950e1161e Mon Sep 17 00:00:00 2001 From: AI Engineer Date: Fri, 5 Jun 2026 08:39:33 +0800 Subject: [PATCH] publish v1.5.2 --- debug/debug_sync.go | 22 ++++++++++++++++++++++ debug/go.mod | 3 +++ go.mod | 8 ++++---- go.sum | 16 ++++++++-------- test_idx.sh | 5 +++++ test_unique.sh | 6 ++++++ test_unique_dup.sh | 6 ++++++ unique_race_test.go | 46 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 debug/debug_sync.go create mode 100644 debug/go.mod create mode 100644 test_idx.sh create mode 100644 test_unique.sh create mode 100644 test_unique_dup.sh create mode 100644 unique_race_test.go diff --git a/debug/debug_sync.go b/debug/debug_sync.go new file mode 100644 index 0000000..dcfd2c8 --- /dev/null +++ b/debug/debug_sync.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "apigo.cc/go/db" +) + +func main() { + dbPath := "debug.db" + dbInst := db.GetDB("sqlite://"+dbPath, nil) + schema := ` +== System == +_Table SD + id c10 PK + name v64 U +` + fmt.Println("First sync...") + dbInst.Sync(schema) + + fmt.Println("\nSecond sync...") + dbInst.Sync(schema) +} diff --git a/debug/go.mod b/debug/go.mod new file mode 100644 index 0000000..8bf1a38 --- /dev/null +++ b/debug/go.mod @@ -0,0 +1,3 @@ +module debug + +go 1.26.1 diff --git a/go.mod b/go.mod index 38e3a24..13e7a43 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.25.0 require ( apigo.cc/go/cast v1.5.0 - apigo.cc/go/config v1.5.0 + apigo.cc/go/config v1.5.1 apigo.cc/go/crypto v1.5.0 apigo.cc/go/file v1.5.0 apigo.cc/go/id v1.5.0 apigo.cc/go/jsmod v1.5.0 - apigo.cc/go/log v1.5.0 + apigo.cc/go/log v1.5.4 apigo.cc/go/redis v1.5.0 apigo.cc/go/safe v1.5.0 apigo.cc/go/shell v1.5.0 @@ -32,9 +32,9 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - golang.org/x/crypto v0.51.0 // indirect + golang.org/x/crypto v0.52.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.44.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.72.0 // indirect diff --git a/go.sum b/go.sum index f806fae..251beae 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ apigo.cc/go/cast v1.5.0 h1:UBGJtFQ8eJPMQXs37cUgqd7YQo1zI9opuSDBDmn2/pE= apigo.cc/go/cast v1.5.0/go.mod h1:z2GW5p5WCZGEqVVIJUdhl232vRbLf2Qu4EDlEakX/D8= -apigo.cc/go/config v1.5.0 h1:Yuz9QEb11XXG4XkhDi/ueT2M1T3Q9PElE5tiakvjehs= -apigo.cc/go/config v1.5.0/go.mod h1:jdMiDLPa9gzB8/FFZvm9jOopUqdxb7XSX+0OeWcZZUM= +apigo.cc/go/config v1.5.1 h1:rpj7oCzlsDV3f2/YK3Pb+CHbfr2DL5Vyyv6VNkobJP4= +apigo.cc/go/config v1.5.1/go.mod h1:jdMiDLPa9gzB8/FFZvm9jOopUqdxb7XSX+0OeWcZZUM= apigo.cc/go/crypto v1.5.0 h1:Nxz7a6VKCdvaF258IU0NkjQyureOLxfR308Sy2iftUI= apigo.cc/go/crypto v1.5.0/go.mod h1:F9M6nXv+5328r1ZwbTvI6fcr8VdgqHVzALOcsdv6ntE= apigo.cc/go/encoding v1.5.0 h1:EJNdRVDOMoI2DAvZwQNQTbYuqB/6zsEzvg7lS5pQI+I= @@ -12,8 +12,8 @@ apigo.cc/go/id v1.5.0 h1:MjNWPhBhDsoXaLeJDv/0wfJmVMU9EvOs8pWYfsTQ6e8= apigo.cc/go/id v1.5.0/go.mod h1:qhu4a1/KLc/XcBpcsRu+mXZt7U7Wvd9zMcPs4VspuPA= apigo.cc/go/jsmod v1.5.0 h1:JgQtJNiJWy1NOP9AzE8NX5VXJkpO/x3GqLsCCSny5Ec= apigo.cc/go/jsmod v1.5.0/go.mod h1:bmyeZtOAP/j5am+YRnaiM89smysK24K7ebk0koFtsSw= -apigo.cc/go/log v1.5.0 h1:kQuLLtbt33mEuc/xJVcy8NODXkso/QKSZWNclKrSpsI= -apigo.cc/go/log v1.5.0/go.mod h1:Djy+I5aLhGB/EjwRz4KHqkVEz584IAD55FAFiIfInuo= +apigo.cc/go/log v1.5.4 h1:LNyU4v09gfcnZOY53ctnXoKzo45FHoEcPR33lk6PBaY= +apigo.cc/go/log v1.5.4/go.mod h1:Djy+I5aLhGB/EjwRz4KHqkVEz584IAD55FAFiIfInuo= apigo.cc/go/rand v1.5.0 h1:1o8hh8fhdBuk1/h02IvugvamuT3dkWbVJrqEJVQKB2E= apigo.cc/go/rand v1.5.0/go.mod h1:Lh98S2dm9UY0X+M+kNQQEKyXHG5pcCKSFPyXN0QCGdk= apigo.cc/go/redis v1.5.0 h1:VXNDqzKj87BchF7ubDEH+T6lp8NrjeK0izU4ooo7u1A= @@ -68,15 +68,15 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= diff --git a/test_idx.sh b/test_idx.sh new file mode 100644 index 0000000..353e9ce --- /dev/null +++ b/test_idx.sh @@ -0,0 +1,5 @@ +rm -f test_idx.db +sqlite3 test_idx.db "CREATE TABLE test (name TEXT);" +sqlite3 test_idx.db "CREATE INDEX idx_name ON test(name);" +sqlite3 test_idx.db "CREATE UNIQUE INDEX IF NOT EXISTS idx_name ON test(name);" +echo "Result code: $?" diff --git a/test_unique.sh b/test_unique.sh new file mode 100644 index 0000000..2d774f5 --- /dev/null +++ b/test_unique.sh @@ -0,0 +1,6 @@ +rm -f test_unique.db +sqlite3 test_unique.db "CREATE TABLE test (name TEXT);" +sqlite3 test_unique.db "INSERT INTO test (name) VALUES ('a');" +sqlite3 test_unique.db "INSERT INTO test (name) VALUES ('b');" +sqlite3 test_unique.db "CREATE UNIQUE INDEX uk_test_name ON test(name);" +echo "Result code: $?" diff --git a/test_unique_dup.sh b/test_unique_dup.sh new file mode 100644 index 0000000..af9aad6 --- /dev/null +++ b/test_unique_dup.sh @@ -0,0 +1,6 @@ +rm -f test_unique.db +sqlite3 test_unique.db "CREATE TABLE test (name TEXT);" +sqlite3 test_unique.db "INSERT INTO test (name) VALUES ('a');" +sqlite3 test_unique.db "INSERT INTO test (name) VALUES ('a');" +sqlite3 test_unique.db "CREATE UNIQUE INDEX uk_test_name ON test(name);" +echo "Result code: $?" diff --git a/unique_race_test.go b/unique_race_test.go new file mode 100644 index 0000000..af75832 --- /dev/null +++ b/unique_race_test.go @@ -0,0 +1,46 @@ +package db + +import ( + "fmt" + "os" + "testing" +) + +func TestCheckTable_DuplicateUnique(t *testing.T) { + dbPath := "test_unique_race.db" + _ = os.Remove(dbPath) + defer os.Remove(dbPath) + + dbInst := GetDB("sqlite://"+dbPath, nil) + + schema := ` +== System == +_Table SD + id c10 PK + name v64 U +` + // First sync + err := dbInst.Sync(schema) + if err != nil { + t.Fatalf("First sync failed: %v", err) + } + + // Insert duplicates to ensure recreation fails + dbInst.Exec("INSERT INTO _Table (id, name) VALUES ('1', 'dup')") + dbInst.Exec("INSERT INTO _Table (id, name) VALUES ('2', 'dup')") // Will fail if unique constraint works, but wait, the unique index is already there, so we can't insert duplicates! + // Wait, we CAN'T insert duplicates because the first sync created the index. + // But in the user's log, there ARE duplicates? Or maybe there are NO duplicates, but the engine just complains when it recreates the index on existing data? + // Ah, if there are NO duplicates, CREATE UNIQUE INDEX will SUCCEED. + // So why did the user get UNIQUE constraint failed? + // BECAUSE THERE WERE DUPLICATES! + // Why would there be duplicates in _Table? + // Let's just do the second sync and see if it tries to execute CREATE UNIQUE INDEX. + + // Print statements will be inside Schema.go for a moment. + + // Second sync (simulate restart) + err = dbInst.Sync(schema) + if err != nil { + t.Fatalf("Second sync failed: %v", err) + } +}