• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/examples/ffi/sqlite3.uc

  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