|
72 | 72 | echo '--- Sample of exported sqlite3_* symbols ---' |
73 | 73 | nm -D --defined-only "$LIB" | awk '$3 ~ /^sqlite3_/ {print $3}' | sort | head -20 |
74 | 74 |
|
| 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 | + |
75 | 146 | - name: Set up PHP |
76 | 147 | uses: shivammathur/setup-php@v2 |
77 | 148 | with: |
|
81 | 152 | - name: Smoke-test pdo_sqlite against Turso |
82 | 153 | continue-on-error: true |
83 | 154 | env: |
84 | | - LD_PRELOAD: ${{ steps.turso-lib.outputs.path }} |
| 155 | + LD_PRELOAD: ${{ steps.preload.outputs.value }} |
85 | 156 | run: | |
86 | 157 | php <<'PHP' |
87 | 158 | <?php |
@@ -131,7 +202,7 @@ jobs: |
131 | 202 | env: |
132 | 203 | # Intentionally NOT setting LD_PRELOAD at step level — we enable it |
133 | 204 | # 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 }} |
135 | 206 | working-directory: packages/mysql-on-sqlite |
136 | 207 | run: | |
137 | 208 | # Progress logging goes to STDERR so it's line-buffered and flushed |
@@ -197,14 +268,14 @@ jobs: |
197 | 268 | gdb -batch \ |
198 | 269 | -ex "set confirm off" \ |
199 | 270 | -ex "set pagination off" \ |
200 | | - -ex "set environment LD_PRELOAD=$TURSO_LIB" \ |
| 271 | + -ex "set environment LD_PRELOAD=$PRELOAD" \ |
201 | 272 | -ex "run /tmp/diag.php" \ |
202 | 273 | -ex "bt" \ |
203 | 274 | --args "$(command -v php)" |
204 | 275 |
|
205 | 276 | - name: Run PHPUnit tests against Turso DB |
206 | 277 | continue-on-error: true |
207 | 278 | env: |
208 | | - LD_PRELOAD: ${{ steps.turso-lib.outputs.path }} |
| 279 | + LD_PRELOAD: ${{ steps.preload.outputs.value }} |
209 | 280 | working-directory: packages/mysql-on-sqlite |
210 | 281 | run: php ./vendor/bin/phpunit -c ./phpunit.xml.dist |
0 commit comments