Skip to content

Commit 3bae638

Browse files
committed
Add compat shim for pdo_sqlite's non-_v2 function calls
pdo_sqlite calls sqlite3_create_function, sqlite3_prepare, etc., but Turso only exports the _v2 variants. Without an override, those symbols fall through to the system libsqlite3 which then operates on a Turso handle and segfaults (confirmed via gdb backtrace). Build a tiny shim library with wrappers that delegate to the _v2 variants and LD_PRELOAD it before Turso.
1 parent 4c1e3da commit 3bae638

1 file changed

Lines changed: 75 additions & 4 deletions

File tree

.github/workflows/phpunit-tests-turso.yml

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,77 @@ jobs:
7272
echo '--- Sample of exported sqlite3_* symbols ---'
7373
nm -D --defined-only "$LIB" | awk '$3 ~ /^sqlite3_/ {print $3}' | sort | head -20
7474
75+
# Turso only exports the _v2 variants of several functions, but PHP's
76+
# pdo_sqlite calls the older names (sqlite3_create_function, sqlite3_prepare,
77+
# etc.). Without an override, those symbols fall through to the system
78+
# libsqlite3 at runtime, which then operates on a Turso-allocated handle
79+
# and segfaults. This shim provides the missing names as thin wrappers
80+
# that delegate to the _v2 variants; LD_PRELOAD'd before Turso, it makes
81+
# pdo_sqlite see a complete sqlite3 C API backed entirely by Turso.
82+
- name: Build pdo_sqlite compatibility shim
83+
id: shim
84+
run: |
85+
cat > /tmp/turso-compat-shim.c <<'C'
86+
typedef struct sqlite3 sqlite3;
87+
typedef struct sqlite3_stmt sqlite3_stmt;
88+
typedef struct sqlite3_value sqlite3_value;
89+
typedef struct sqlite3_context sqlite3_context;
90+
91+
extern int sqlite3_create_function_v2(
92+
sqlite3 *db, const char *name, int n_arg, int enc, void *app,
93+
void (*x_func)(sqlite3_context*, int, sqlite3_value**),
94+
void (*x_step)(sqlite3_context*, int, sqlite3_value**),
95+
void (*x_final)(sqlite3_context*),
96+
void (*x_destroy)(void*));
97+
98+
int sqlite3_create_function(
99+
sqlite3 *db, const char *name, int n_arg, int enc, void *app,
100+
void (*x_func)(sqlite3_context*, int, sqlite3_value**),
101+
void (*x_step)(sqlite3_context*, int, sqlite3_value**),
102+
void (*x_final)(sqlite3_context*))
103+
{
104+
return sqlite3_create_function_v2(db, name, n_arg, enc, app,
105+
x_func, x_step, x_final, 0);
106+
}
107+
108+
extern int sqlite3_prepare_v2(sqlite3 *db, const char *sql, int nbytes,
109+
sqlite3_stmt **out_stmt, const char **tail);
110+
111+
int sqlite3_prepare(sqlite3 *db, const char *sql, int nbytes,
112+
sqlite3_stmt **out_stmt, const char **tail)
113+
{
114+
return sqlite3_prepare_v2(db, sql, nbytes, out_stmt, tail);
115+
}
116+
117+
extern int sqlite3_create_collation_v2(sqlite3 *db, const char *name,
118+
int enc, void *ctx,
119+
int (*cmp)(void*, int, const void*, int, const void*),
120+
void (*destroy)(void*));
121+
122+
int sqlite3_create_collation(sqlite3 *db, const char *name, int enc,
123+
void *ctx,
124+
int (*cmp)(void*, int, const void*, int, const void*))
125+
{
126+
return sqlite3_create_collation_v2(db, name, enc, ctx, cmp, 0);
127+
}
128+
129+
extern long long sqlite3_value_int64(sqlite3_value *v);
130+
int sqlite3_value_int(sqlite3_value *v) { return (int)sqlite3_value_int64(v); }
131+
132+
extern void sqlite3_result_int64(sqlite3_context *ctx, long long v);
133+
void sqlite3_result_int(sqlite3_context *ctx, int v) { sqlite3_result_int64(ctx, (long long)v); }
134+
C
135+
136+
SHIM=/tmp/libturso-compat-shim.so
137+
gcc -shared -fPIC -Wall -O2 -o "$SHIM" /tmp/turso-compat-shim.c
138+
echo "Shim library: $SHIM"
139+
nm -D --defined-only "$SHIM" | awk '$3 ~ /^sqlite3_/ {print $3}'
140+
echo "path=$SHIM" >> "$GITHUB_OUTPUT"
141+
142+
- name: Combine LD_PRELOAD paths
143+
id: preload
144+
run: echo "value=${{ steps.shim.outputs.path }}:${{ steps.turso-lib.outputs.path }}" >> "$GITHUB_OUTPUT"
145+
75146
- name: Set up PHP
76147
uses: shivammathur/setup-php@v2
77148
with:
@@ -81,7 +152,7 @@ jobs:
81152
- name: Smoke-test pdo_sqlite against Turso
82153
continue-on-error: true
83154
env:
84-
LD_PRELOAD: ${{ steps.turso-lib.outputs.path }}
155+
LD_PRELOAD: ${{ steps.preload.outputs.value }}
85156
run: |
86157
php <<'PHP'
87158
<?php
@@ -131,7 +202,7 @@ jobs:
131202
env:
132203
# Intentionally NOT setting LD_PRELOAD at step level — we enable it
133204
# only inside the script so gdb itself doesn't link against Turso.
134-
TURSO_LIB: ${{ steps.turso-lib.outputs.path }}
205+
PRELOAD: ${{ steps.preload.outputs.value }}
135206
working-directory: packages/mysql-on-sqlite
136207
run: |
137208
# Progress logging goes to STDERR so it's line-buffered and flushed
@@ -197,14 +268,14 @@ jobs:
197268
gdb -batch \
198269
-ex "set confirm off" \
199270
-ex "set pagination off" \
200-
-ex "set environment LD_PRELOAD=$TURSO_LIB" \
271+
-ex "set environment LD_PRELOAD=$PRELOAD" \
201272
-ex "run /tmp/diag.php" \
202273
-ex "bt" \
203274
--args "$(command -v php)"
204275
205276
- name: Run PHPUnit tests against Turso DB
206277
continue-on-error: true
207278
env:
208-
LD_PRELOAD: ${{ steps.turso-lib.outputs.path }}
279+
LD_PRELOAD: ${{ steps.preload.outputs.value }}
209280
working-directory: packages/mysql-on-sqlite
210281
run: php ./vendor/bin/phpunit -c ./phpunit.xml.dist

0 commit comments

Comments
 (0)