1 // sqlite3.uc - SQLite3 FFI wrapper example 2 // Demonstrates FFI with complex structs, callbacks, and memory management 3 4 import * as ffi from 'ffi'; 5 6 // Constants 7 const SQLITE_OK = 0; 8 const SQLITE_ROW = 100; 9 const SQLITE_DONE = 101; 10 const SQLITE_ERROR = 1; 11 12 // ============================================================================ 13 // run - Complete SQLite3 FFI Demo 14 // 15 // Demonstrates FFI usage with SQLite3, covering: dynamic library loading, 16 // struct and pointer types, prepared statements, parameter binding, result 17 // column extraction, and error handling. Shows how persistent ctype buffers 18 // are required for string arguments since native ucode string memory may not 19 // remain valid across native calls. 20 // 21 // Steps performed: 22 // 1. Load sqlite3 library from system paths (tries x86_64, i386, then PATH) 23 // 2. Query library version info (libversion, libversion_number) 24 // 3. Open an in-memory database using sqlite3_open() 25 // 4. Create a users table with CREATE TABLE via sqlite3_exec() 26 // 5. Insert two rows using prepared statements with parameter binding 27 // - Uses ffi.string() to create persistent char[N] ctype buffers, then 28 // passes .ptr() to bind_text() so the memory outlives the call 29 // 6. Execute SELECT with step/column extraction via prepared statements 30 // 7. Demonstrate error handling with an invalid query via sqlite3_exec() 31 // 8. Report error details using sqlite3_errmsg() and sqlite3_errcode() 32 // 9. Close the database via sqlite3_close() 33 // 34 // Usage: 35 // ucode examples/ffi/sqlite3.uc 36 // 37 // Dependencies: libsqlite3 installed on the system 38 // ============================================================================ 39 40 function run() { 41 print("=== SQLite3 FFI Demo ===\n"); 42 43 // Load sqlite3 library with cdefs 44 print("Loading sqlite3 library...\n"); 45 let sqlite3lib = null; 46 47 let cdefs = ` 48 typedef struct sqlite3 sqlite3; 49 typedef struct sqlite3_stmt sqlite3_stmt; 50 typedef void sqlite3_destructor_type; 51 52 const char *sqlite3_libversion(void); 53 int sqlite3_libversion_number(void); 54 int sqlite3_open(const char *, void **); 55 int sqlite3_close(void *); 56 int sqlite3_exec(void *, const char *, int, int, int); 57 int sqlite3_prepare_v2(void *, const char *, int, void **, const char **); 58 int sqlite3_reset(void *); 59 int sqlite3_finalize(void *); 60 int sqlite3_step(void *); 61 int sqlite3_bind_text(void *, int, const char *, int, int); 62 int sqlite3_bind_int(void *, int, int); 63 const unsigned char *sqlite3_column_text(void *, int); 64 int sqlite3_column_int(void *, int); 65 double sqlite3_column_double(void *, int); 66 const char *sqlite3_errmsg(void *); 67 int sqlite3_errcode(void *); 68 int sqlite3_changes(void *); 69 `; 70 71 try { 72 sqlite3lib = ffi.dlopen('/usr/lib/x86_64-linux-gnu/libsqlite3.so.0', false, cdefs); 73 } catch (e) { 74 try { 75 sqlite3lib = ffi.dlopen('/usr/lib/i386-linux-gnu/libsqlite3.so.0', false, cdefs); 76 } catch (e2) { 77 try { 78 sqlite3lib = ffi.dlopen('sqlite3', false, cdefs); 79 } catch (e3) { 80 sqlite3lib = null; 81 } 82 } 83 } 84 85 if (!sqlite3lib) { 86 print("Could not load sqlite3 library. Install libsqlite3-dev to run this demo.\n"); 87 print("Skipping demo.\n"); 88 return; 89 } 90 91 print("Library loaded successfully.\n\n"); 92 93 // 1. Version info 94 let version_ptr = sqlite3lib.sqlite3_libversion(); 95 let version = ffi.string(version_ptr); 96 print("SQLite version: ", version, "\n"); 97 print("Version number: ", sqlite3lib.sqlite3_libversion_number(), "\n\n"); 98 99 // 2. Create in-memory database 100 print("Creating in-memory database...\n"); 101 let db = ffi.ctype('void *', null); 102 let rc = sqlite3lib.sqlite3_open(':memory:', db.ptr()); 103 if (rc !== SQLITE_OK) 104 die("Failed to open database: error " + rc); 105 106 // 3. Create schema 107 print("Creating tables...\n"); 108 let createSQL = "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT)"; 109 rc = sqlite3lib.sqlite3_exec(db, createSQL, 0, 0, 0); 110 if (rc !== SQLITE_OK) 111 die("Failed to create users table"); 112 113 // 4. Insert data 114 print("Inserting users...\n"); 115 let insertSQL = "INSERT INTO users (name, email) VALUES (?, ?)"; 116 let stmtPtr = ffi.ctype('void *', null); 117 rc = sqlite3lib.sqlite3_prepare_v2(db, insertSQL, -1, stmtPtr.ptr(), null); 118 if (rc !== SQLITE_OK) 119 die("Failed to prepare insert"); 120 let insertStmt = stmtPtr; 121 122 // Insert Alice 123 let aliceName = ffi.string('Alice'); 124 let aliceEmail = ffi.string('alice@example.com'); 125 sqlite3lib.sqlite3_bind_text(insertStmt, 1, aliceName.ptr(), -1, 0); 126 sqlite3lib.sqlite3_bind_text(insertStmt, 2, aliceEmail.ptr(), -1, 0); 127 rc = sqlite3lib.sqlite3_step(insertStmt); 128 if (rc !== SQLITE_DONE) 129 die("Insert Alice failed"); 130 131 // Insert Bob 132 sqlite3lib.sqlite3_reset(insertStmt); 133 let bobName = ffi.string('Bob'); 134 let bobEmail = ffi.string('bob@example.com'); 135 sqlite3lib.sqlite3_bind_text(insertStmt, 1, bobName.ptr(), -1, 0); 136 sqlite3lib.sqlite3_bind_text(insertStmt, 2, bobEmail.ptr(), -1, 0); 137 rc = sqlite3lib.sqlite3_step(insertStmt); 138 if (rc !== SQLITE_DONE) 139 die("Insert Bob failed"); 140 141 sqlite3lib.sqlite3_finalize(insertStmt); 142 print("Inserted ", sqlite3lib.sqlite3_changes(db), " rows\n\n"); 143 144 // 5. Query data 145 print("Querying users...\n"); 146 let selectSQL = "SELECT id, name, email FROM users ORDER BY id"; 147 rc = sqlite3lib.sqlite3_prepare_v2(db, selectSQL, -1, stmtPtr.ptr(), null); 148 let selectStmt = stmtPtr; 149 while (sqlite3lib.sqlite3_step(selectStmt) === SQLITE_ROW) { 150 let id = sqlite3lib.sqlite3_column_int(selectStmt, 0); 151 let name_ptr = sqlite3lib.sqlite3_column_text(selectStmt, 1); 152 let email_ptr = sqlite3lib.sqlite3_column_text(selectStmt, 2); 153 let name = ffi.string(name_ptr); 154 let email = ffi.string(email_ptr); 155 print(" User: ", id, " - ", name, " <", email, ">\n"); 156 } 157 sqlite3lib.sqlite3_finalize(selectStmt); 158 159 // 6. Error handling demo 160 print("\n=== Error Handling Demo ===\n"); 161 rc = sqlite3lib.sqlite3_exec(db, "SELECT * FROM nonexistent_table", 0, 0, 0); 162 if (rc !== SQLITE_OK) { 163 let errmsg_ptr = sqlite3lib.sqlite3_errmsg(db); 164 let errmsg = ffi.string(errmsg_ptr); 165 print("Caught error: ", errmsg, "\n"); 166 print("Error code: ", sqlite3lib.sqlite3_errcode(db), "\n"); 167 } 168 169 // Clean up 170 sqlite3lib.sqlite3_close(db); 171 172 print("\n=== Demo Complete ===\n"); 173 } 174 175 // Run demo 176 run();
This page was automatically generated by LXR 0.3.1. • OpenWrt