publish v1.5.2
This commit is contained in:
parent
74b9bfe511
commit
41e2bac5e2
22
debug/debug_sync.go
Normal file
22
debug/debug_sync.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
3
debug/go.mod
Normal file
3
debug/go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module debug
|
||||||
|
|
||||||
|
go 1.26.1
|
||||||
8
go.mod
8
go.mod
@ -4,12 +4,12 @@ go 1.25.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/go/cast v1.5.0
|
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/crypto v1.5.0
|
||||||
apigo.cc/go/file v1.5.0
|
apigo.cc/go/file v1.5.0
|
||||||
apigo.cc/go/id v1.5.0
|
apigo.cc/go/id v1.5.0
|
||||||
apigo.cc/go/jsmod 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/redis v1.5.0
|
||||||
apigo.cc/go/safe v1.5.0
|
apigo.cc/go/safe v1.5.0
|
||||||
apigo.cc/go/shell 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/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // 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/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
|
golang.org/x/text v0.37.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/libc v1.72.0 // indirect
|
modernc.org/libc v1.72.0 // indirect
|
||||||
|
|||||||
16
go.sum
16
go.sum
@ -1,7 +1,7 @@
|
|||||||
apigo.cc/go/cast v1.5.0 h1:UBGJtFQ8eJPMQXs37cUgqd7YQo1zI9opuSDBDmn2/pE=
|
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/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.1 h1:rpj7oCzlsDV3f2/YK3Pb+CHbfr2DL5Vyyv6VNkobJP4=
|
||||||
apigo.cc/go/config v1.5.0/go.mod h1:jdMiDLPa9gzB8/FFZvm9jOopUqdxb7XSX+0OeWcZZUM=
|
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 h1:Nxz7a6VKCdvaF258IU0NkjQyureOLxfR308Sy2iftUI=
|
||||||
apigo.cc/go/crypto v1.5.0/go.mod h1:F9M6nXv+5328r1ZwbTvI6fcr8VdgqHVzALOcsdv6ntE=
|
apigo.cc/go/crypto v1.5.0/go.mod h1:F9M6nXv+5328r1ZwbTvI6fcr8VdgqHVzALOcsdv6ntE=
|
||||||
apigo.cc/go/encoding v1.5.0 h1:EJNdRVDOMoI2DAvZwQNQTbYuqB/6zsEzvg7lS5pQI+I=
|
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/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 h1:JgQtJNiJWy1NOP9AzE8NX5VXJkpO/x3GqLsCCSny5Ec=
|
||||||
apigo.cc/go/jsmod v1.5.0/go.mod h1:bmyeZtOAP/j5am+YRnaiM89smysK24K7ebk0koFtsSw=
|
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.4 h1:LNyU4v09gfcnZOY53ctnXoKzo45FHoEcPR33lk6PBaY=
|
||||||
apigo.cc/go/log v1.5.0/go.mod h1:Djy+I5aLhGB/EjwRz4KHqkVEz584IAD55FAFiIfInuo=
|
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 h1:1o8hh8fhdBuk1/h02IvugvamuT3dkWbVJrqEJVQKB2E=
|
||||||
apigo.cc/go/rand v1.5.0/go.mod h1:Lh98S2dm9UY0X+M+kNQQEKyXHG5pcCKSFPyXN0QCGdk=
|
apigo.cc/go/rand v1.5.0/go.mod h1:Lh98S2dm9UY0X+M+kNQQEKyXHG5pcCKSFPyXN0QCGdk=
|
||||||
apigo.cc/go/redis v1.5.0 h1:VXNDqzKj87BchF7ubDEH+T6lp8NrjeK0izU4ooo7u1A=
|
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.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 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
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.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||||
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
|
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 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
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 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||||
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
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 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
||||||
|
|||||||
5
test_idx.sh
Normal file
5
test_idx.sh
Normal file
@ -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: $?"
|
||||||
6
test_unique.sh
Normal file
6
test_unique.sh
Normal file
@ -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: $?"
|
||||||
6
test_unique_dup.sh
Normal file
6
test_unique_dup.sh
Normal file
@ -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: $?"
|
||||||
46
unique_race_test.go
Normal file
46
unique_race_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user