Skip to content

Commit f540ff5

Browse files
committed
Add support for bounded JDBC cursor
1 parent ceb6549 commit f540ff5

21 files changed

Lines changed: 2559 additions & 396 deletions

‎server/client_error.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const (
1111
PG_ERROR_CODE_FEATURE_NOT_SUPPORTED = "0A000"
1212
PG_ERROR_CODE_PROTOCOL_VIOLATION = "08P01"
1313
PG_ERROR_CODE_INVALID_PARAMETER_VALUE = "22023"
14+
PG_ERROR_CODE_INVALID_BINARY_REPRESENTATION = "22P03"
1415
)
1516

1617
type ClientError struct {

‎server/config.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
const (
12-
VERSION = "2.1.0"
12+
VERSION = "2.2.0"
1313

1414
ENV_LOG_LEVEL = "LOG_LEVEL"
1515
ENV_AUDIT_ENABLED = "AUDIT_ENABLED"

‎server/duckdb_client.go‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,6 @@ func (client *DuckdbClient) QueryContext(ctx context.Context, query string, args
141141
return client.Db.QueryContext(ctx, query, args...)
142142
}
143143

144-
func (client *DuckdbClient) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
145-
LogDebug(client.Config, "Preparing DuckDB statement:", query)
146-
return client.Db.PrepareContext(ctx, query)
147-
}
148-
149144
func (client *DuckdbClient) ExecContext(ctx context.Context, query string, args ...map[string]string) (sql.Result, error) {
150145
LogDebug(client.Config, "Executing DuckDB:", query)
151146
if len(args) == 0 {
@@ -185,19 +180,6 @@ func (client *DuckdbClient) Close() {
185180
client.Connector.Close()
186181
}
187182

188-
func (client *DuckdbClient) RecreateDb() error {
189-
db, connector, err := client.openDatabase()
190-
if err != nil {
191-
return fmt.Errorf("failed to recreate DuckDB: %w", err)
192-
}
193-
194-
client.Db.Close()
195-
client.Connector.Close()
196-
client.Db = db
197-
client.Connector = connector
198-
return nil
199-
}
200-
201183
func replaceNamedStringArgs(query string, args map[string]string) string {
202184
for key, value := range args {
203185
query = strings.ReplaceAll(

‎server/duckdb_client_test.go‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ func TestSearchReaderSeesExternalCommits(t *testing.T) {
5151
t.Fatal(err)
5252
}
5353
check("after")
54-
if err := reader.RecreateDb(); err != nil {
55-
t.Fatal(err)
56-
}
57-
check("after")
5854
if _, err := writer.ExecContext(ctx, "UPDATE search_store.main.products SET name = 'latest'"); err != nil {
5955
t.Fatal(err)
6056
}

‎server/embedding_client_test.go‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,24 @@ func TestEmbeddingClientAndLiteralCache(t *testing.T) {
6565
prepared := &PreparedStatement{VectorParameters: map[int]SearchParameterSpec{
6666
1: {Dimensions: 2, RequireNonZero: true},
6767
}}
68-
_, prepared, err = queryHandler.HandleBindQuery(&pgproto3.Bind{Parameters: [][]byte{[]byte("dog")}}, prepared)
68+
_, portal1, err := queryHandler.HandleBindQuery(context.Background(), &pgproto3.Bind{Parameters: [][]byte{[]byte("dog")}}, prepared)
69+
defer portal1.Close()
6970
if err != nil {
7071
t.Fatal(err)
7172
}
72-
vector := prepared.Variables[0].([]float32)
73+
vector := portal1.Variables[0].([]float32)
7374
if len(vector) != 2 || vector[0] != 0.6 || vector[1] != 0.8 {
7475
t.Fatalf("unexpected bound embedding: %#v", vector)
7576
}
7677
prepared = &PreparedStatement{VectorParameters: map[int]SearchParameterSpec{
7778
1: {Dimensions: 2, RequireNonZero: true, LiteralText: &dog},
7879
}}
79-
_, prepared, err = queryHandler.HandleBindQuery(&pgproto3.Bind{}, prepared)
80+
_, portal2, err := queryHandler.HandleBindQuery(context.Background(), &pgproto3.Bind{}, prepared)
81+
defer portal2.Close()
8082
if err != nil {
8183
t.Fatal(err)
8284
}
83-
vector = prepared.Variables[0].([]float32)
85+
vector = portal2.Variables[0].([]float32)
8486
if len(vector) != 2 || vector[0] != 0.6 || vector[1] != 0.8 {
8587
t.Fatalf("unexpected hidden literal embedding: %#v", vector)
8688
}

‎server/main_test.go‎

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func TestRuntimeManagerSharesLazyInitialization(t *testing.T) {
5454
}
5555
}
5656

57-
func TestRuntimeManagerWaitsForExpiredRuntimeToCloseBeforeRecreating(t *testing.T) {
57+
func TestRuntimeManagerReplacesExpiredRuntimeWhileOldReadersFinish(t *testing.T) {
5858
var attempts atomic.Int32
5959
runtime := fakeServerRuntime()
6060
manager := &RuntimeManager{
@@ -101,14 +101,24 @@ func TestRuntimeManagerWaitsForExpiredRuntimeToCloseBeforeRecreating(t *testing.
101101
}()
102102

103103
select {
104-
case <-acquireDone:
104+
case err := <-acquireDone:
105+
if err != nil {
106+
runtime.RequestMu.RUnlock()
107+
t.Fatal(err)
108+
}
109+
case <-time.After(time.Second):
105110
runtime.RequestMu.RUnlock()
106-
t.Fatal("new runtime was created before expired runtime closed")
111+
t.Fatal("new queries blocked behind retired runtime")
112+
}
113+
select {
114+
case <-expired:
115+
runtime.RequestMu.RUnlock()
116+
t.Fatal("old runtime closed with active reader")
107117
default:
108118
}
109-
if got := attempts.Load(); got != 0 {
119+
if got := attempts.Load(); got != 1 {
110120
runtime.RequestMu.RUnlock()
111-
t.Fatalf("runtime creation attempts before close = %d, want 0", got)
121+
t.Fatalf("initializations = %d", got)
112122
}
113123

114124
runtime.RequestMu.RUnlock()
@@ -117,12 +127,16 @@ func TestRuntimeManagerWaitsForExpiredRuntimeToCloseBeforeRecreating(t *testing.
117127
case <-time.After(time.Second):
118128
t.Fatal("expired runtime did not close")
119129
}
120-
if err := <-acquireDone; err != nil {
121-
t.Fatalf("runtime acquisition after close failed: %v", err)
122-
}
123130
if got := attempts.Load(); got != 1 {
124131
t.Fatalf("runtime creation attempts after close = %d, want 1", got)
125132
}
133+
manager.mu.Lock()
134+
replacement := manager.runtime
135+
manager.mu.Unlock()
136+
if replacement == nil || replacement == runtime {
137+
t.Fatal("closing the retired runtime removed its replacement")
138+
}
139+
126140
}
127141

128142
func TestRuntimeManagerRetriesAfterInitializationFailure(t *testing.T) {

0 commit comments

Comments
 (0)