389 lines
9.2 KiB
Text
389 lines
9.2 KiB
Text
.section Libraries
|
|
.topic sql.overview
|
|
.title dvxSql -- SQL Database Interface
|
|
.toc 0 dvxSql -- SQL Database Interface
|
|
.default
|
|
.index dvxSql
|
|
.index SQL
|
|
.index SQLite
|
|
.index Database
|
|
|
|
.h2 dvxSql -- SQL Database Interface
|
|
|
|
High-level wrapper around SQLite3 for DVX applications. Manages database connections and result set cursors via integer handles so BASIC code never touches raw pointers. All handles are 1-based; 0 indicates an error or invalid handle.
|
|
|
|
Header: sql/dvxSql.h
|
|
|
|
.h3 Limits
|
|
|
|
.table
|
|
Constant Value Description
|
|
-------- ----- -----------
|
|
MAX_DBS 16 Maximum number of simultaneously open databases.
|
|
MAX_CURSORS 64 Maximum number of simultaneously open result set cursors.
|
|
.endtable
|
|
|
|
.h3 Handle Model
|
|
|
|
Database and cursor handles are int32_t values. A successful open or query returns a handle greater than zero. Handle 0 is reserved as the invalid/error sentinel. Closing a database automatically finalizes all cursors that belong to it.
|
|
|
|
.link sql.db Database Operations
|
|
.link sql.cursor Cursor Operations
|
|
.link sql.utility Utility Functions
|
|
.link sql.example Example
|
|
|
|
.topic sql.db
|
|
.title Database Operations
|
|
.toc 1 Database Operations
|
|
.index dvxSqlOpen
|
|
.index dvxSqlClose
|
|
.index dvxSqlExec
|
|
.index dvxSqlError
|
|
.index dvxSqlAffectedRows
|
|
|
|
.h2 Database Operations
|
|
|
|
.h3 dvxSqlOpen
|
|
|
|
.code
|
|
int32_t dvxSqlOpen(const char *path);
|
|
.endcode
|
|
|
|
Open a SQLite database file. Creates the file if it does not exist.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
path Path to the database file.
|
|
.endtable
|
|
|
|
Returns a database handle greater than 0 on success, or 0 on error (null path, open failure, or no free slots).
|
|
|
|
.h3 dvxSqlClose
|
|
|
|
.code
|
|
void dvxSqlClose(int32_t db);
|
|
.endcode
|
|
|
|
Close a database and free all associated resources. Any open cursors belonging to this database are automatically finalized.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
db Database handle returned by dvxSqlOpen.
|
|
.endtable
|
|
|
|
Safe to call with an invalid handle (no-op).
|
|
|
|
.h3 dvxSqlExec
|
|
|
|
.code
|
|
bool dvxSqlExec(int32_t db, const char *sql);
|
|
.endcode
|
|
|
|
Execute one or more SQL statements that return no result rows. Suitable for DDL (CREATE TABLE, DROP TABLE, etc.) and DML (INSERT, UPDATE, DELETE).
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
db Database handle.
|
|
sql SQL statement(s) to execute.
|
|
.endtable
|
|
|
|
Returns true on success, false on error. On failure, the error message is available via dvxSqlError. On success, the affected row count is available via dvxSqlAffectedRows.
|
|
|
|
.h3 dvxSqlError
|
|
|
|
.code
|
|
const char *dvxSqlError(int32_t db);
|
|
.endcode
|
|
|
|
Return the last error message for a database handle. The returned string is stored internally and valid until the next operation on the same handle.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
db Database handle.
|
|
.endtable
|
|
|
|
Returns the error string, or "Invalid database handle" if the handle is invalid.
|
|
|
|
.h3 dvxSqlAffectedRows
|
|
|
|
.code
|
|
int32_t dvxSqlAffectedRows(int32_t db);
|
|
.endcode
|
|
|
|
Return the number of rows inserted, updated, or deleted by the last dvxSqlExec call on this handle.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
db Database handle.
|
|
.endtable
|
|
|
|
Returns the row count, or 0 if the handle is invalid.
|
|
|
|
.topic sql.cursor
|
|
.title Cursor Operations
|
|
.toc 1 Cursor Operations
|
|
.index dvxSqlQuery
|
|
.index dvxSqlNext
|
|
.index dvxSqlEof
|
|
.index dvxSqlFieldCount
|
|
.index dvxSqlFieldName
|
|
.index dvxSqlFieldText
|
|
.index dvxSqlFieldByName
|
|
.index dvxSqlFieldInt
|
|
.index dvxSqlFieldDbl
|
|
.index dvxSqlFreeResult
|
|
|
|
.h2 Cursor Operations
|
|
|
|
Result set cursors are created by dvxSqlQuery and must be freed with dvxSqlFreeResult when no longer needed. A new cursor is positioned before the first row; call dvxSqlNext to advance to the first row before reading field values.
|
|
|
|
.h3 dvxSqlQuery
|
|
|
|
.code
|
|
int32_t dvxSqlQuery(int32_t db, const char *sql);
|
|
.endcode
|
|
|
|
Execute a SELECT query and return a cursor handle for iterating the results. The cursor is positioned before the first row.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
db Database handle.
|
|
sql SQL SELECT statement.
|
|
.endtable
|
|
|
|
Returns a cursor handle greater than 0 on success, or 0 on error (invalid handle, null SQL, SQL syntax error, or no free cursor slots). On failure, the error message is available via dvxSqlError on the database handle.
|
|
|
|
.h3 dvxSqlNext
|
|
|
|
.code
|
|
bool dvxSqlNext(int32_t rs);
|
|
.endcode
|
|
|
|
Advance the cursor to the next row.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle returned by dvxSqlQuery.
|
|
.endtable
|
|
|
|
Returns true if a row is now available for reading, false if the cursor has reached the end or the handle is invalid.
|
|
|
|
.h3 dvxSqlEof
|
|
|
|
.code
|
|
bool dvxSqlEof(int32_t rs);
|
|
.endcode
|
|
|
|
Test whether the cursor is past the last row.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
.endtable
|
|
|
|
Returns true if the cursor is exhausted or the handle is invalid, false otherwise.
|
|
|
|
.h3 dvxSqlFieldCount
|
|
|
|
.code
|
|
int32_t dvxSqlFieldCount(int32_t rs);
|
|
.endcode
|
|
|
|
Return the number of columns in the result set.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
.endtable
|
|
|
|
Returns the column count, or 0 if the handle is invalid.
|
|
|
|
.h3 dvxSqlFieldName
|
|
|
|
.code
|
|
const char *dvxSqlFieldName(int32_t rs, int32_t col);
|
|
.endcode
|
|
|
|
Return the name of a column by index.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
col Column index (0-based).
|
|
.endtable
|
|
|
|
Returns the column name, or "" if the handle or index is invalid.
|
|
|
|
.h3 dvxSqlFieldText
|
|
|
|
.code
|
|
const char *dvxSqlFieldText(int32_t rs, int32_t col);
|
|
.endcode
|
|
|
|
Return the value of a column as a string.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
col Column index (0-based).
|
|
.endtable
|
|
|
|
Returns the text value, or "" if the handle or index is invalid or the value is NULL.
|
|
|
|
.h3 dvxSqlFieldByName
|
|
|
|
.code
|
|
const char *dvxSqlFieldByName(int32_t rs, const char *name);
|
|
.endcode
|
|
|
|
Return the value of a column identified by name as a string. The name match is case-insensitive.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
name Column name (case-insensitive).
|
|
.endtable
|
|
|
|
Returns the text value, or "" if the handle is invalid, the name is NULL, or no column with that name exists.
|
|
|
|
.h3 dvxSqlFieldInt
|
|
|
|
.code
|
|
int32_t dvxSqlFieldInt(int32_t rs, int32_t col);
|
|
.endcode
|
|
|
|
Return the value of a column as a 32-bit integer.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
col Column index (0-based).
|
|
.endtable
|
|
|
|
Returns the integer value, or 0 if the handle or index is invalid.
|
|
|
|
.h3 dvxSqlFieldDbl
|
|
|
|
.code
|
|
double dvxSqlFieldDbl(int32_t rs, int32_t col);
|
|
.endcode
|
|
|
|
Return the value of a column as a double-precision floating point number.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
col Column index (0-based).
|
|
.endtable
|
|
|
|
Returns the double value, or 0.0 if the handle or index is invalid.
|
|
|
|
.h3 dvxSqlFreeResult
|
|
|
|
.code
|
|
void dvxSqlFreeResult(int32_t rs);
|
|
.endcode
|
|
|
|
Close a result set cursor and free its resources. Must be called for every cursor returned by dvxSqlQuery.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
rs Cursor handle.
|
|
.endtable
|
|
|
|
Safe to call with an invalid handle (no-op).
|
|
|
|
.topic sql.utility
|
|
.title Utility Functions
|
|
.toc 1 Utility Functions
|
|
.index dvxSqlEscape
|
|
|
|
.h2 Utility Functions
|
|
|
|
.h3 dvxSqlEscape
|
|
|
|
.code
|
|
int32_t dvxSqlEscape(const char *src, char *dst, int32_t dstSize);
|
|
.endcode
|
|
|
|
Escape a string for safe inclusion in SQL string literals. Doubles single quotes so that O'Brien becomes O''Brien.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
src Source string to escape.
|
|
dst Destination buffer for the escaped string.
|
|
dstSize Size of the destination buffer in bytes.
|
|
.endtable
|
|
|
|
Returns the length of the escaped string (not including the null terminator), or -1 if the buffer was too small or any parameter is NULL/invalid.
|
|
|
|
.topic sql.example
|
|
.title Example Usage
|
|
.toc 1 Example Usage
|
|
.index SQL Example
|
|
|
|
.h2 Example Usage
|
|
|
|
.h3 Creating a Table and Inserting Data
|
|
|
|
.code
|
|
int32_t db = dvxSqlOpen("mydata.db");
|
|
if (!db) {
|
|
// handle error
|
|
}
|
|
|
|
dvxSqlExec(db, "CREATE TABLE IF NOT EXISTS contacts ("
|
|
"id INTEGER PRIMARY KEY, "
|
|
"name TEXT, "
|
|
"phone TEXT)");
|
|
|
|
dvxSqlExec(db, "INSERT INTO contacts (name, phone) "
|
|
"VALUES ('Alice', '555-0100')");
|
|
.endcode
|
|
|
|
.h3 Querying and Iterating Results
|
|
|
|
.code
|
|
int32_t rs = dvxSqlQuery(db, "SELECT id, name, phone FROM contacts");
|
|
if (!rs) {
|
|
printf("Error: %s\n", dvxSqlError(db));
|
|
}
|
|
|
|
while (dvxSqlNext(rs)) {
|
|
int32_t id = dvxSqlFieldInt(rs, 0);
|
|
const char *name = dvxSqlFieldText(rs, 1);
|
|
const char *phone = dvxSqlFieldText(rs, 2);
|
|
printf("%d: %s -- %s\n", id, name, phone);
|
|
}
|
|
|
|
dvxSqlFreeResult(rs);
|
|
dvxSqlClose(db);
|
|
.endcode
|
|
|
|
.h3 Escaping User Input
|
|
|
|
.code
|
|
char escaped[512];
|
|
dvxSqlEscape(userInput, escaped, sizeof(escaped));
|
|
|
|
char sql[1024];
|
|
snprintf(sql, sizeof(sql),
|
|
"INSERT INTO notes (text) VALUES ('%s')", escaped);
|
|
dvxSqlExec(db, sql);
|
|
.endcode
|