koffi 0.9.27 → 0.9.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/benchmark/CMakeLists.txt +12 -3
- package/benchmark/atoi_cc.cc +1 -1
- package/benchmark/raylib_cc.cc +2 -2
- package/benchmark/raylib_koffi.js +1 -1
- package/benchmark/raylib_node_ffi.js +1 -8
- package/package.json +1 -1
- package/src/call_arm32.cc +2 -2
- package/src/call_arm32_fwd.S +12 -12
- package/src/util.cc +20 -5
- package/src/util.hh +5 -3
- package/vendor/sqlite3/shell.c +31 -22
- package/vendor/sqlite3/sqlite3.c +329 -132
- package/vendor/sqlite3/sqlite3.h +10 -6
package/README.md
CHANGED
|
@@ -265,7 +265,7 @@ Once this is done, you can execute each implementation, e.g. `build/atoi_cc` or
|
|
|
265
265
|
|
|
266
266
|
## atoi results
|
|
267
267
|
|
|
268
|
-
Here are some results from 2022-04-24 on my
|
|
268
|
+
Here are some results from 2022-04-24 on Linux on my machine (AMD® Ryzen™ 7 5800H 16G):
|
|
269
269
|
|
|
270
270
|
```sh
|
|
271
271
|
$ build/atoi_cc
|
|
@@ -278,7 +278,7 @@ Time: 1.10s
|
|
|
278
278
|
|
|
279
279
|
$ ./atoi_koffi.js
|
|
280
280
|
Iterations: 20000000
|
|
281
|
-
Time:
|
|
281
|
+
Time: 1.91s
|
|
282
282
|
|
|
283
283
|
# Note: the Node-FFI version does a few setTimeout calls to force the GC to run (around 20
|
|
284
284
|
# for the example below), without which Node will consume all memory because the GC never appears
|
|
@@ -289,29 +289,29 @@ Iterations: 20000000
|
|
|
289
289
|
Time: 640.49s
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
-
And on
|
|
292
|
+
And on Windows on the same machine (AMD® Ryzen™ 7 5800H 16G):
|
|
293
293
|
|
|
294
294
|
```sh
|
|
295
295
|
$ build\atoi_cc.exe
|
|
296
296
|
Iterations: 20000000
|
|
297
|
-
Time: 0.
|
|
297
|
+
Time: 0.25s
|
|
298
298
|
|
|
299
299
|
$ node atoi_napi.js
|
|
300
300
|
Iterations: 20000000
|
|
301
|
-
Time:
|
|
301
|
+
Time: 1.94s
|
|
302
302
|
|
|
303
303
|
$ node atoi_koffi.js
|
|
304
304
|
Iterations: 20000000
|
|
305
|
-
Time:
|
|
305
|
+
Time: 3.15s
|
|
306
306
|
|
|
307
307
|
$ node atoi_node_ffi.js
|
|
308
308
|
Iterations: 20000000
|
|
309
|
-
Time:
|
|
309
|
+
Time: 267.20s
|
|
310
310
|
```
|
|
311
311
|
|
|
312
312
|
## Raylib results
|
|
313
313
|
|
|
314
|
-
Here are some results from 2022-04-24 on my
|
|
314
|
+
Here are some results from 2022-04-24 on Linux on my machine (AMD® Ryzen™ 7 5800H 16G):
|
|
315
315
|
|
|
316
316
|
```sh
|
|
317
317
|
$ build/raylib_cc
|
|
@@ -327,18 +327,18 @@ Iterations: 100
|
|
|
327
327
|
Time: 27.13s
|
|
328
328
|
```
|
|
329
329
|
|
|
330
|
-
And on
|
|
330
|
+
And on Windows on the same machine (AMD® Ryzen™ 7 5800H 16G):
|
|
331
331
|
|
|
332
332
|
```sh
|
|
333
333
|
$ build\raylib_cc.exe
|
|
334
334
|
Iterations: 100
|
|
335
|
-
Time:
|
|
335
|
+
Time: 8.39s
|
|
336
336
|
|
|
337
337
|
$ node raylib_koffi.js
|
|
338
338
|
Iterations: 100
|
|
339
|
-
Time:
|
|
339
|
+
Time: 11.51s
|
|
340
340
|
|
|
341
341
|
$ node raylib_node_ffi.js
|
|
342
342
|
Iterations: 100
|
|
343
|
-
Time:
|
|
343
|
+
Time: 32.47s
|
|
344
344
|
```
|
package/benchmark/CMakeLists.txt
CHANGED
|
@@ -16,7 +16,10 @@ project(koffi C CXX ASM)
|
|
|
16
16
|
|
|
17
17
|
find_package(CNoke)
|
|
18
18
|
|
|
19
|
-
set(CMAKE_CXX_STANDARD
|
|
19
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
20
|
+
|
|
21
|
+
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|
22
|
+
find_package(Threads REQUIRED)
|
|
20
23
|
|
|
21
24
|
if(NOT TARGET koffi)
|
|
22
25
|
add_subdirectory(.. koffi)
|
|
@@ -27,6 +30,7 @@ add_subdirectory(../test test)
|
|
|
27
30
|
|
|
28
31
|
add_executable(atoi_cc atoi_cc.cc ../vendor/libcc/libcc.cc)
|
|
29
32
|
target_include_directories(atoi_cc PRIVATE ..)
|
|
33
|
+
target_link_libraries(atoi_cc PRIVATE Threads::Threads)
|
|
30
34
|
|
|
31
35
|
if(WIN32)
|
|
32
36
|
target_compile_definitions(atoi_cc PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
|
@@ -35,19 +39,24 @@ endif()
|
|
|
35
39
|
|
|
36
40
|
add_node_addon(NAME atoi_napi SOURCES atoi_napi.cc ../vendor/libcc/libcc.cc)
|
|
37
41
|
target_include_directories(atoi_napi PRIVATE .. ../vendor/node-addon-api)
|
|
42
|
+
target_link_libraries(atoi_napi PRIVATE Threads::Threads)
|
|
38
43
|
|
|
39
44
|
if(WIN32)
|
|
40
45
|
target_compile_definitions(atoi_napi PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
|
41
46
|
target_link_libraries(atoi_napi PRIVATE ws2_32)
|
|
47
|
+
else()
|
|
48
|
+
target_link_libraries(atoi_napi PRIVATE dl)
|
|
42
49
|
endif()
|
|
43
50
|
|
|
44
51
|
# ---- Raylib ----
|
|
45
52
|
|
|
46
|
-
add_executable(raylib_cc
|
|
53
|
+
add_executable(raylib_cc raylib_cc.cc ../vendor/libcc/libcc.cc)
|
|
47
54
|
target_include_directories(raylib_cc PRIVATE ..)
|
|
48
|
-
|
|
55
|
+
target_link_libraries(raylib_cc PRIVATE Threads::Threads raylib)
|
|
49
56
|
|
|
50
57
|
if(WIN32)
|
|
51
58
|
target_compile_definitions(raylib_cc PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
|
52
59
|
target_link_libraries(raylib_cc PRIVATE ws2_32)
|
|
60
|
+
else()
|
|
61
|
+
target_link_libraries(raylib_cc PRIVATE dl)
|
|
53
62
|
endif()
|
package/benchmark/atoi_cc.cc
CHANGED
|
@@ -36,7 +36,7 @@ int Main(int argc, char **argv)
|
|
|
36
36
|
int64_t start = GetMonotonicTime();
|
|
37
37
|
|
|
38
38
|
for (int i = 0; i < iterations; i++) {
|
|
39
|
-
sum
|
|
39
|
+
sum = sum + (uint64_t)atoi(strings[i % RG_LEN(strings)]);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Help prevent optimisation of loop
|
package/benchmark/raylib_cc.cc
CHANGED
|
@@ -31,13 +31,13 @@ int Main(int argc, char **argv)
|
|
|
31
31
|
SetWindowState(FLAG_WINDOW_HIDDEN);
|
|
32
32
|
InitWindow(640, 480, "Raylib Test");
|
|
33
33
|
|
|
34
|
-
Image img = GenImageColor(800, 600,
|
|
34
|
+
Image img = GenImageColor(800, 600, Color { .r = 0, .g = 0, .b = 0, .a = 255 });
|
|
35
35
|
Font font = GetFontDefault();
|
|
36
36
|
|
|
37
37
|
int64_t start = GetMonotonicTime();
|
|
38
38
|
|
|
39
39
|
for (int i = 0; i < iterations; i++) {
|
|
40
|
-
ImageClearBackground(&img,
|
|
40
|
+
ImageClearBackground(&img, Color { .r = 0, .g = 0, .b = 0, .a = 255 });
|
|
41
41
|
|
|
42
42
|
for (int j = 0; j < 3600; j++) {
|
|
43
43
|
const char *text = "Hello World!";
|
|
@@ -82,7 +82,7 @@ function main() {
|
|
|
82
82
|
}
|
|
83
83
|
console.log('Iterations:', iterations);
|
|
84
84
|
|
|
85
|
-
let lib_filename = path.dirname(__filename) + '/
|
|
85
|
+
let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
|
|
86
86
|
let lib = koffi.load(lib_filename);
|
|
87
87
|
|
|
88
88
|
const InitWindow = lib.cdecl('InitWindow', 'void', ['int', 'int', 'string']);
|
|
@@ -98,14 +98,7 @@ function main() {
|
|
|
98
98
|
}
|
|
99
99
|
console.log('Iterations:', iterations);
|
|
100
100
|
|
|
101
|
-
let
|
|
102
|
-
if (Number.isNaN(iterations))
|
|
103
|
-
throw new Error('Not a valid number');
|
|
104
|
-
if (iterations < 1)
|
|
105
|
-
throw new Error('Value must be positive');
|
|
106
|
-
console.log('Iterations:', iterations);
|
|
107
|
-
|
|
108
|
-
let lib_filename = path.dirname(__filename) + '/test/build/raylib' + koffi.extension;
|
|
101
|
+
let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
|
|
109
102
|
|
|
110
103
|
const r = ffi.Library(lib_filename, {
|
|
111
104
|
InitWindow: ['void', ['int', 'int', 'string']],
|
package/package.json
CHANGED
package/src/call_arm32.cc
CHANGED
|
@@ -233,10 +233,10 @@ static Napi::Value TranslateCall(const Napi::CallbackInfo &info)
|
|
|
233
233
|
// Return through registers unless it's too big
|
|
234
234
|
if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
|
|
235
235
|
return env.Null();
|
|
236
|
-
if (RG_UNLIKELY(!call.AllocStack(4 * 4, 8, &gpr_ptr)))
|
|
237
|
-
return env.Null();
|
|
238
236
|
if (RG_UNLIKELY(!call.AllocStack(8 * 8, 8, &vec_ptr)))
|
|
239
237
|
return env.Null();
|
|
238
|
+
if (RG_UNLIKELY(!call.AllocStack(4 * 4, 8, &gpr_ptr)))
|
|
239
|
+
return env.Null();
|
|
240
240
|
if (func->ret.use_memory) {
|
|
241
241
|
if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
|
|
242
242
|
return env.Null();
|
package/src/call_arm32_fwd.S
CHANGED
|
@@ -56,22 +56,22 @@
|
|
|
56
56
|
|
|
57
57
|
// Prepare general purpose argument registers from array passed by caller.
|
|
58
58
|
.macro forward_int
|
|
59
|
-
ldr r3, [r1,
|
|
60
|
-
ldr r2, [r1,
|
|
61
|
-
ldr r0, [r1,
|
|
62
|
-
ldr r1, [r1,
|
|
59
|
+
ldr r3, [r1, 12]
|
|
60
|
+
ldr r2, [r1, 8]
|
|
61
|
+
ldr r0, [r1, 0]
|
|
62
|
+
ldr r1, [r1, 4]
|
|
63
63
|
.endm
|
|
64
64
|
|
|
65
65
|
// Prepare vector argument registers from array passed by caller.
|
|
66
66
|
.macro forward_vec
|
|
67
|
-
vldr d7, [r1,
|
|
68
|
-
vldr d6, [r1,
|
|
69
|
-
vldr d5, [r1,
|
|
70
|
-
vldr d4, [r1,
|
|
71
|
-
vldr d3, [r1,
|
|
72
|
-
vldr d2, [r1,
|
|
73
|
-
vldr d1, [r1,
|
|
74
|
-
vldr d0, [r1,
|
|
67
|
+
vldr d7, [r1, 72]
|
|
68
|
+
vldr d6, [r1, 64]
|
|
69
|
+
vldr d5, [r1, 56]
|
|
70
|
+
vldr d4, [r1, 48]
|
|
71
|
+
vldr d3, [r1, 40]
|
|
72
|
+
vldr d2, [r1, 32]
|
|
73
|
+
vldr d1, [r1, 24]
|
|
74
|
+
vldr d0, [r1, 16]
|
|
75
75
|
.endm
|
|
76
76
|
|
|
77
77
|
ForwardCallGG:
|
package/src/util.cc
CHANGED
|
@@ -81,23 +81,38 @@ const char *CallData::PushString(const Napi::Value &value)
|
|
|
81
81
|
{
|
|
82
82
|
RG_ASSERT(value.IsString());
|
|
83
83
|
|
|
84
|
+
const Size SmallSize = 32;
|
|
85
|
+
|
|
84
86
|
Napi::Env env = value.Env();
|
|
85
87
|
napi_status status;
|
|
86
88
|
|
|
89
|
+
Span<char> buf;
|
|
87
90
|
size_t len = 0;
|
|
88
|
-
status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
|
|
89
|
-
RG_ASSERT(status == napi_ok);
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
buf.len =
|
|
92
|
+
// Optimize for small strings
|
|
93
|
+
buf.len = SmallSize;
|
|
93
94
|
if (RG_UNLIKELY(!AllocHeap(buf.len, 1, &buf.ptr)))
|
|
94
95
|
return nullptr;
|
|
95
|
-
|
|
96
96
|
if (RG_UNLIKELY(napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len) != napi_ok)) {
|
|
97
97
|
ThrowError<Napi::Error>(env, "Failed to convert string to UTF-8");
|
|
98
98
|
return nullptr;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// Slow path for bigger strings
|
|
102
|
+
if (len >= SmallSize - 1) {
|
|
103
|
+
status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
|
|
104
|
+
RG_ASSERT(status == napi_ok);
|
|
105
|
+
RG_ASSERT(len >= SmallSize);
|
|
106
|
+
|
|
107
|
+
buf.len = (Size)len + 1;
|
|
108
|
+
if (RG_UNLIKELY(!AllocHeap(buf.len - SmallSize, 1)))
|
|
109
|
+
return nullptr;
|
|
110
|
+
if (RG_UNLIKELY(napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len) != napi_ok)) {
|
|
111
|
+
ThrowError<Napi::Error>(env, "Failed to convert string to UTF-8");
|
|
112
|
+
return nullptr;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
101
116
|
return buf.ptr;
|
|
102
117
|
}
|
|
103
118
|
|
package/src/util.hh
CHANGED
|
@@ -101,8 +101,8 @@ public:
|
|
|
101
101
|
|
|
102
102
|
template <typename T = void>
|
|
103
103
|
bool AllocStack(Size size, Size align, T **out_ptr = nullptr);
|
|
104
|
-
template <typename T>
|
|
105
|
-
bool AllocHeap(Size size, Size align, T **out_ptr);
|
|
104
|
+
template <typename T = void>
|
|
105
|
+
bool AllocHeap(Size size, Size align, T **out_ptr = nullptr);
|
|
106
106
|
|
|
107
107
|
const char *PushString(const Napi::Value &value);
|
|
108
108
|
bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest);
|
|
@@ -151,7 +151,9 @@ bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
|
|
|
151
151
|
heap_mem->ptr += delta;
|
|
152
152
|
heap_mem->len -= delta;
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
if (out_ptr) {
|
|
155
|
+
*out_ptr = (T *)ptr;
|
|
156
|
+
}
|
|
155
157
|
return true;
|
|
156
158
|
}
|
|
157
159
|
|
package/vendor/sqlite3/shell.c
CHANGED
|
@@ -7964,9 +7964,14 @@ static int zipfileFilter(
|
|
|
7964
7964
|
zipfileCursorErr(pCsr, "zipfile() function requires an argument");
|
|
7965
7965
|
return SQLITE_ERROR;
|
|
7966
7966
|
}else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
|
|
7967
|
+
static const u8 aEmptyBlob = 0;
|
|
7967
7968
|
const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
|
|
7968
7969
|
int nBlob = sqlite3_value_bytes(argv[0]);
|
|
7969
7970
|
assert( pTab->pFirstEntry==0 );
|
|
7971
|
+
if( aBlob==0 ){
|
|
7972
|
+
aBlob = &aEmptyBlob;
|
|
7973
|
+
nBlob = 0;
|
|
7974
|
+
}
|
|
7970
7975
|
rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
|
|
7971
7976
|
pCsr->pFreeEntry = pTab->pFirstEntry;
|
|
7972
7977
|
pTab->pFirstEntry = pTab->pLastEntry = 0;
|
|
@@ -19906,7 +19911,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
19906
19911
|
|
|
19907
19912
|
if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
|
|
19908
19913
|
char *zTable = 0; /* Insert data into this table */
|
|
19909
|
-
char *zSchema =
|
|
19914
|
+
char *zSchema = 0; /* within this schema (may default to "main") */
|
|
19910
19915
|
char *zFile = 0; /* Name of file to extra content from */
|
|
19911
19916
|
sqlite3_stmt *pStmt = NULL; /* A statement */
|
|
19912
19917
|
int nCol; /* Number of columns in the table */
|
|
@@ -19915,11 +19920,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
19915
19920
|
int needCommit; /* True to COMMIT or ROLLBACK at end */
|
|
19916
19921
|
int nSep; /* Number of bytes in p->colSeparator[] */
|
|
19917
19922
|
char *zSql; /* An SQL statement */
|
|
19923
|
+
char *zFullTabName; /* Table name with schema if applicable */
|
|
19918
19924
|
ImportCtx sCtx; /* Reader context */
|
|
19919
19925
|
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
|
|
19920
19926
|
int eVerbose = 0; /* Larger for more console output */
|
|
19921
19927
|
int nSkip = 0; /* Initial lines to skip */
|
|
19922
19928
|
int useOutputMode = 1; /* Use output mode to determine separators */
|
|
19929
|
+
char *zCreate = 0; /* CREATE TABLE statement text */
|
|
19923
19930
|
|
|
19924
19931
|
failIfSafeMode(p, "cannot run .import in safe mode");
|
|
19925
19932
|
memset(&sCtx, 0, sizeof(sCtx));
|
|
@@ -20042,7 +20049,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
20042
20049
|
import_cleanup(&sCtx);
|
|
20043
20050
|
goto meta_command_exit;
|
|
20044
20051
|
}
|
|
20045
|
-
/* Below, resources must be freed before exit. */
|
|
20046
20052
|
if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
|
|
20047
20053
|
char zSep[2];
|
|
20048
20054
|
zSep[1] = 0;
|
|
@@ -20054,11 +20060,17 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
20054
20060
|
output_c_string(p->out, zSep);
|
|
20055
20061
|
utf8_printf(p->out, "\n");
|
|
20056
20062
|
}
|
|
20063
|
+
/* Below, resources must be freed before exit. */
|
|
20057
20064
|
while( (nSkip--)>0 ){
|
|
20058
20065
|
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
|
|
20059
20066
|
}
|
|
20060
|
-
|
|
20061
|
-
|
|
20067
|
+
if( zSchema!=0 ){
|
|
20068
|
+
zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable);
|
|
20069
|
+
}else{
|
|
20070
|
+
zFullTabName = sqlite3_mprintf("\"%w\"", zTable);
|
|
20071
|
+
}
|
|
20072
|
+
zSql = sqlite3_mprintf("SELECT * FROM %s", zFullTabName);
|
|
20073
|
+
if( zSql==0 || zFullTabName==0 ){
|
|
20062
20074
|
import_cleanup(&sCtx);
|
|
20063
20075
|
shell_out_of_memory();
|
|
20064
20076
|
}
|
|
@@ -20066,11 +20078,10 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
20066
20078
|
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
|
20067
20079
|
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
|
|
20068
20080
|
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
|
|
20069
|
-
char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
|
|
20070
|
-
zSchema, zTable);
|
|
20071
20081
|
sqlite3 *dbCols = 0;
|
|
20072
20082
|
char *zRenames = 0;
|
|
20073
20083
|
char *zColDefs;
|
|
20084
|
+
zCreate = sqlite3_mprintf("CREATE TABLE %s", zFullTabName);
|
|
20074
20085
|
while( xRead(&sCtx) ){
|
|
20075
20086
|
zAutoColumn(sCtx.z, &dbCols, 0);
|
|
20076
20087
|
if( sCtx.cTerm!=sCtx.cColSep ) break;
|
|
@@ -20084,9 +20095,12 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
20084
20095
|
}
|
|
20085
20096
|
assert(dbCols==0);
|
|
20086
20097
|
if( zColDefs==0 ){
|
|
20098
|
+
utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
|
|
20099
|
+
import_fail:
|
|
20087
20100
|
sqlite3_free(zCreate);
|
|
20101
|
+
sqlite3_free(zSql);
|
|
20102
|
+
sqlite3_free(zFullTabName);
|
|
20088
20103
|
import_cleanup(&sCtx);
|
|
20089
|
-
utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
|
|
20090
20104
|
rc = 1;
|
|
20091
20105
|
goto meta_command_exit;
|
|
20092
20106
|
}
|
|
@@ -20097,22 +20111,18 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
20097
20111
|
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
|
|
20098
20112
|
if( rc ){
|
|
20099
20113
|
utf8_printf(stderr, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
|
|
20100
|
-
|
|
20101
|
-
import_cleanup(&sCtx);
|
|
20102
|
-
rc = 1;
|
|
20103
|
-
goto meta_command_exit;
|
|
20114
|
+
goto import_fail;
|
|
20104
20115
|
}
|
|
20105
20116
|
sqlite3_free(zCreate);
|
|
20117
|
+
zCreate = 0;
|
|
20106
20118
|
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
|
20107
20119
|
}
|
|
20108
|
-
sqlite3_free(zSql);
|
|
20109
20120
|
if( rc ){
|
|
20110
20121
|
if (pStmt) sqlite3_finalize(pStmt);
|
|
20111
20122
|
utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
|
|
20112
|
-
|
|
20113
|
-
rc = 1;
|
|
20114
|
-
goto meta_command_exit;
|
|
20123
|
+
goto import_fail;
|
|
20115
20124
|
}
|
|
20125
|
+
sqlite3_free(zSql);
|
|
20116
20126
|
nCol = sqlite3_column_count(pStmt);
|
|
20117
20127
|
sqlite3_finalize(pStmt);
|
|
20118
20128
|
pStmt = 0;
|
|
@@ -20122,8 +20132,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
20122
20132
|
import_cleanup(&sCtx);
|
|
20123
20133
|
shell_out_of_memory();
|
|
20124
20134
|
}
|
|
20125
|
-
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO
|
|
20126
|
-
zSchema, zTable);
|
|
20135
|
+
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zFullTabName);
|
|
20127
20136
|
j = strlen30(zSql);
|
|
20128
20137
|
for(i=1; i<nCol; i++){
|
|
20129
20138
|
zSql[j++] = ',';
|
|
@@ -20135,14 +20144,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|
|
20135
20144
|
utf8_printf(p->out, "Insert using: %s\n", zSql);
|
|
20136
20145
|
}
|
|
20137
20146
|
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
|
20138
|
-
sqlite3_free(zSql);
|
|
20139
20147
|
if( rc ){
|
|
20140
20148
|
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
|
|
20141
20149
|
if (pStmt) sqlite3_finalize(pStmt);
|
|
20142
|
-
|
|
20143
|
-
rc = 1;
|
|
20144
|
-
goto meta_command_exit;
|
|
20150
|
+
goto import_fail;
|
|
20145
20151
|
}
|
|
20152
|
+
sqlite3_free(zSql);
|
|
20153
|
+
sqlite3_free(zFullTabName);
|
|
20146
20154
|
needCommit = sqlite3_get_autocommit(p->db);
|
|
20147
20155
|
if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
|
|
20148
20156
|
do{
|
|
@@ -22636,7 +22644,8 @@ static int process_input(ShellState *p){
|
|
|
22636
22644
|
qss = QSS_Start;
|
|
22637
22645
|
}
|
|
22638
22646
|
}
|
|
22639
|
-
if( nSql
|
|
22647
|
+
if( nSql ){
|
|
22648
|
+
/* This may be incomplete. Let the SQL parser deal with that. */
|
|
22640
22649
|
errCnt += runOneSqlLine(p, zSql, p->in, startline);
|
|
22641
22650
|
}
|
|
22642
22651
|
free(zSql);
|