[SCM] Lisaac library sqlite-binding branch, master, updated. 9d61fabb17ed6436a34b2f07c79ca21f693c0c7e

Jeremy (none) jeremy at jeremy-desktop.
Tue Nov 11 01:23:26 UTC 2008


The following commit has been merged in the master branch:
commit 9d61fabb17ed6436a34b2f07c79ca21f693c0c7e
Author: Jeremy <jeremy at jeremy-desktop.(none)>
Date:   Mon Nov 10 20:23:12 2008 -0500

    Initial import

diff --git a/example.li b/example.li
new file mode 100644
index 0000000..19838bc
--- /dev/null
+++ b/example.li
@@ -0,0 +1,71 @@
+Section Header
+	+ name := EXAMPLE;
+
+Section Public
+	- main <-
+	(
+		+ d:SQLITE;
+		+ s:SQLITE_STATEMENT;
+
+		"Opening database example.db\n".print;
+		d := SQLITE.open("example.db");
+
+		d.is_empty.if {
+			"Creating our names table\n".print;
+			( d.exec ("CREATE TABLE names (id INTEGER, name VARCHAR(20))") != SQLITE.ok ).if {
+				"Could not create new names table!\n".print;
+				OBJECT.die_with_code 1;
+			};
+		};
+
+		( COMMAND_LINE.upper > 1 ).if {
+			"Inserting new names from the command line\n".print;
+			s := d.prepare("INSERT INTO names VALUES (?,?)");
+			1.to (COMMAND_LINE.upper) do { i:INTEGER;
+				s.bind 1 to_integer i;
+				s.bind 2 to_string (COMMAND_LINE.item i);
+				( s.step != SQLITE.done ).if {
+					( "Error inserting new record: " + d.errmsg + "\n").print;
+					OBJECT.die_with_code 1;
+				};
+				("   Inserted: " + (COMMAND_LINE.item i) + "\n").print;
+				s.reset;
+			};
+			s.finalize;
+		};
+
+		"Querying all records from the names table\n".print;
+
+		/*
+		s := d.prepare("SELECT * FROM names");
+		{ s.step = SQLITE.row }.while_do {
+			( s.as_string 0 + " " + s.as_string 1 + "\n").print;
+		};
+		s.finalize;
+		*/
+
+		/*
+		s := d.prepare("SELECT * FROM names");
+		s.foreach {
+			( s.as_string 0 + " " + s.as_string 1 + "\n").print;
+		};
+		s.finalize;
+		*/
+
+		d.foreach "SELECT * FROM names" do { row:SQLITE_STATEMENT;
+			( "   " + row.as_string 0 + " " + row.as_string 1 + "\n").print;
+		} else {
+			"   No results found...\n".print;
+			"       use ./example Name1 Name2 Name3 to add some\n".print;
+		};
+
+		"Querying all records with id > 10 from the names table\n".print;
+		d.foreach "SELECT * FROM names WHERE id > 10" do { row:SQLITE_STATEMENT;
+			( "   " + row.as_string 0 + " " + row.as_string 1 + "\n").print;
+		} else {
+			"   No results found for id > 10\n".print;
+		};
+
+		"Closing database\n".print;
+		d.close;
+	);
diff --git a/sqlite.li b/sqlite.li
new file mode 100644
index 0000000..6359cc6
--- /dev/null
+++ b/sqlite.li
@@ -0,0 +1,351 @@
+Section Header
+
+	// Binding of SQLite (http://sqlite.org) for Lisaac
+
+	+ name     := SQLITE;
+
+	- copyright := "2008, Jeremy Cowgar";
+
+	- comment   := "SQLite binding";
+
+	- external := `
+	#include <sqlite3.h>
+	int rc;
+	sqlite3 *db;
+	sqlite3_stmt *stmt;
+	`;
+
+Section Inherit
+
+	- parent_object:OBJECT := OBJECT;
+
+Section Public
+
+	+ pointer :POINTER := NULL;
+	// Internal pointer to the "sqlite3 *" database handle.
+
+Section Public
+	// Mode specifiers that can be used in conjunction with `open ... mode ...`
+
+	- open_readonly   :INTEGER := `SQLITE_OPEN_READONLY`:INTEGER;
+	// The database is opened in read-only mode. If the database does not
+	// already exist, an error is returned.
+
+	- open_readwrite  :INTEGER := `SQLITE_OPEN_READWRITE`:INTEGER;
+	// The database is opened for reading and writing if possible, or reading
+	// only if the file is write protected by the operating system. In either
+	// case the database must already exist, otherwise an error is returned.
+	// This is the behavior that is always used for `open`.
+
+	- open_create     :INTEGER := `SQLITE_OPEN_CREATE`:INTEGER;
+	// The database is created if it does not yet exist. This is the behavior
+	// that is always used for `open`.
+
+Section Public
+	// Error/Success codes returned by many SQLITE slots.
+
+	- ok:INTEGER := `SQLITE_OK`:INTEGER;
+	// Successful result
+
+	- error:INTEGER := `SQLITE_ERROR`:INTEGER;
+	// SQL error or missing database
+
+	- internal:INTEGER := `SQLITE_INTERNAL`:INTEGER;
+	// Internal logic error in SQLite
+
+	- perm:INTEGER := `SQLITE_PERM`:INTEGER;
+	// Access permission denied
+
+	- abort:INTEGER := `SQLITE_ABORT`:INTEGER;
+	// Callback routine requested an abort
+
+	- busy:INTEGER := `SQLITE_BUSY`:INTEGER;
+	// The database file is locked
+
+	- locked:INTEGER := `SQLITE_LOCKED`:INTEGER;
+	// A table in the database is locked
+
+	- nomem:INTEGER := `SQLITE_NOMEM`:INTEGER;
+	// A malloc() failed
+
+	- readonly:INTEGER := `SQLITE_READONLY`:INTEGER;
+	// Attempt to write a readonly database
+
+	- interrupt:INTEGER := `SQLITE_INTERRUPT`:INTEGER;
+	// Operation terminated by sqlite3_interrupt()
+
+	- ioerr:INTEGER := `SQLITE_IOERR`:INTEGER;
+	// Some kind of disk I/O error occurred
+
+	- corrupt:INTEGER := `SQLITE_CORRUPT`:INTEGER;
+	// The database disk image is malformed
+
+	- notfound:INTEGER := `SQLITE_NOTFOUND`:INTEGER;
+	// NOT USED. Table or record not found
+
+	- full:INTEGER := `SQLITE_FULL`:INTEGER;
+	// Insertion failed because database is full
+
+	- cantopen:INTEGER := `SQLITE_CANTOPEN`:INTEGER;
+	// Unable to open the database file
+
+	- protocol:INTEGER := `SQLITE_PROTOCOL`:INTEGER;
+	// NOT USED. Database lock protocol error
+
+	- empty:INTEGER := `SQLITE_EMPTY`:INTEGER;
+	// Database is empty
+
+	- schema:INTEGER := `SQLITE_SCHEMA`:INTEGER;
+	// The database schema changed
+
+	- toobig:INTEGER := `SQLITE_TOOBIG`:INTEGER;
+	// String or BLOB exceeds size limit
+
+	- constraint:INTEGER := `SQLITE_CONSTRAINT`:INTEGER;
+	// Abort due to constraint violation
+
+	- mismatch:INTEGER := `SQLITE_MISMATCH`:INTEGER;
+	// Data type mismatch
+
+	- misuse:INTEGER := `SQLITE_MISUSE`:INTEGER;
+	// Library used incorrectly
+
+	- nolfs:INTEGER := `SQLITE_NOLFS`:INTEGER;
+	// Uses OS features not supported on host
+
+	- auth:INTEGER := `SQLITE_AUTH`:INTEGER;
+	// Authorization denied
+
+	- format:INTEGER := `SQLITE_FORMAT`:INTEGER;
+	// Auxiliary database format error
+
+	- range:INTEGER := `SQLITE_RANGE`:INTEGER;
+	// bind column index is out of range
+
+	- notadb:INTEGER := `SQLITE_NOTADB`:INTEGER;
+	// File opened that is not a database file
+
+	- row:INTEGER := `SQLITE_ROW`:INTEGER;
+	// `step` has another row ready
+
+	- done:INTEGER := `SQLITE_DONE`:INTEGER;
+	// `step` has finished executing
+
+Section Public
+	// Open/Close, Create/Destroy
+
+	- set_dbh dbh:POINTER <-
+	// Set the C sqlite3* handle for this connection.
+	(
+		pointer := dbh;
+	);
+
+	- make dbh:POINTER :SELF <-
+	// Clone `SQLITE` with the given `dbh` as the database handle pointer.
+	(
+		+ result:SELF;
+
+		result := SELF.clone;
+		result.set_dbh dbh;
+		result
+	);
+
+	- open filename:ABSTRACT_STRING :SELF <-
+	// Open a SQLite database. The database file is created if it does not
+	// exist. If the `filename` is ":memory:", then a private, temporary
+	// in-memory database is created for the connection. If the `filename`
+	// is empty "" then a private, temporary on-disk database will be
+	// created.
+	(
+		+ result:SELF;
+		+ n_filename:NATIVE_ARRAY[CHARACTER];
+
+		n_filename := filename.to_external;
+
+		( `sqlite3_open(@n_filename, &db)`:INTEGER = SQLITE.ok ).if {
+			result := SELF.make `db`:POINTER;
+		} else {
+			result := SELF.make NULL;
+		};
+
+		result
+	);
+
+	- open filename:ABSTRACT_STRING mode mode:INTEGER :SELF <-
+	// Open a SQLite database in the given `mode`. See `open`,
+	// `open_readonly`, `open_readwrite` and `open_create` for
+	// more information.
+	(
+		+ result:SELF;
+		+ n_filename:NATIVE_ARRAY[CHARACTER];
+		+ rc:INTEGER;
+
+		n_filename := filename.to_external;
+		rc := `sqlite3_open_v2(@n_filename, &db, @mode, NULL)`:INTEGER;
+		( rc = SQLITE.ok ).if {
+			result := SELF.make `db`:POINTER;
+		} else {
+			result := SELF.make NULL;
+		};
+
+		result
+	);
+
+	- close <-
+	// Close the database.
+	(
+		+ dbh :POINTER;
+		dbh := pointer;
+		`sqlite3_close(@dbh)`;
+	);
+
+Section Public
+	// Error information
+
+	- errcode :INTEGER <-
+	// Returns the integer result code of the most recent failed
+	// action. It is possible that it return `ok` if no failure
+	// has taken place.
+	(
+		+ dbh : POINTER;
+		`sqlite3_errcode(@dbh)`:INTEGER
+	);
+
+	- errmsg :STRING <-
+	// Returns the English-language text that describes the most
+	// recent failed action.
+	(
+		+ error_message : NATIVE_ARRAY[CHARACTER];
+		+ dbh : POINTER;
+		+ result : STRING;
+
+		dbh := pointer;
+		error_message := `sqlite3_errmsg(@dbh)`:NATIVE_ARRAY[CHARACTER];
+
+		result := STRING.clone;
+		result.from_external(error_message);
+		result
+	);
+
+Section Public
+	// Querying
+
+	- exec sql:ABSTRACT_STRING :INTEGER <-
+	// Execute one or more SQL statements. See also `prepare`, `changes`
+	// and `total_changes`.
+	(
+		+ dbh    : POINTER;
+		+ a_sql  : NATIVE_ARRAY[CHARACTER];
+
+		dbh    := pointer;
+		a_sql  := sql.to_external;
+		`sqlite3_exec(@dbh, @a_sql, 0, 0, 0)`:INTEGER
+	);
+
+	- prepare sql:ABSTRACT_STRING :SQLITE_STATEMENT <-
+	// Prepare a SQL statement for execution.
+	(
+		+ dbh    : POINTER;
+		+ stmt   : POINTER;
+		+ a_sql  : NATIVE_ARRAY[CHARACTER];
+		+ result : INTEGER;
+		+ o_stmt : SQLITE_STATEMENT;
+
+		dbh    := pointer;
+		a_sql  := sql.to_external;
+		`rc = sqlite3_prepare_v2(@dbh, @a_sql, -1, &stmt, 0)`;
+		result := `rc`:INTEGER;
+		stmt   := `stmt`:POINTER;
+
+		o_stmt := SQLITE_STATEMENT.make stmt;
+		o_stmt
+	);
+
+	- foreach sql:ABSTRACT_STRING do b:BLOCK <-
+	// Execute `sql` and call `b` for each row returned by the `sql`
+	// statement.
+	(
+		+ o_stmt : SQLITE_STATEMENT;
+		o_stmt := prepare(sql);
+		{ o_stmt.step = SQLITE.row }.while_do { b.value o_stmt };
+		o_stmt.finalize;
+	);
+
+	- foreach sql:ABSTRACT_STRING do b:BLOCK else be:BLOCK <-
+	// Execute `sql` and call `b` for each row returned by the `sql`
+	// statement. If no rows are returned execute `be` instead.
+	(
+		+ o_stmt:SQLITE_STATEMENT;
+		+ count:INTEGER;
+
+		count := 0;
+		o_stmt := prepare(sql);
+		{ o_stmt.step = SQLITE.row }.while_do {
+			b.value o_stmt;
+			count := count + 1;
+		};
+
+		o_stmt.finalize;
+
+		( count = 0 ).if be;
+	);
+
+Section Public
+	// Statistics
+
+	- changes :INTEGER <-
+	// Returns the number of row changes caused by INSERT, UPDATE and
+	// DELETE statements during the last SQL statement. See also
+	// `total_changes`.
+	(
+		+ dbh:POINTER;
+		dbh := pointer;
+		`sqlite3_changes(@dbh)`:INTEGER
+	);
+
+	- total_changes :INTEGER <-
+	// Returns the number of row changes caused by INSERT, UPDATE and
+	// DELETE statements since the database connection was opened.
+	// See also `changes`.
+	(
+		+ dbh:POINTER;
+		dbh := pointer;
+		`sqlite3_total_changes(@dbh)`:INTEGER
+	);
+
+	- last_insert_rowid :INTEGER_64 <-
+	// Each entry in an SQLite table has a unique 64-bit signed integer
+	// key called the "rowid". The rowid is always available as an
+	// undeclared column named ROWID, OID, or _ROWID_ as long as those
+	// names are not also used by explicitly declared columns. If the
+	// table has a column of type INTEGER PRIMARY KEY then that column
+	// is another alias for the rowid.
+	//
+	// This routine returns the rowid of the most recent successful
+	// INSERT into the database from the database connection in the
+	// first argument. If no successful INSERTs have ever occurred on
+	// that database connection, zero is returned.
+	(
+		+ dbh:POINTER;
+		dbh := pointer;
+		`sqlite3_last_insert_rowid(@stmt)`:INTEGER_64
+	);
+
+	- is_empty :BOOLEAN <-
+	// Query the "sqlite_master" table to determine if this SQLite
+	// database has any tables. This can be used to see if a call
+	// to `open` has opened or created the database file.
+	(
+		+ s : SQLITE_STATEMENT;
+		+ r : BOOLEAN;
+
+		s := prepare("SELECT COUNT(name) FROM sqlite_master");
+		( s.step = SQLITE.row ).if {
+			r := (s.as_integer(0) = 0);
+		} else {
+			r := TRUE;
+		};
+		s.finalize;
+
+		r
+	);
diff --git a/sqlite_statement.li b/sqlite_statement.li
new file mode 100644
index 0000000..d8837ee
--- /dev/null
+++ b/sqlite_statement.li
@@ -0,0 +1,262 @@
+Section Header
+
+	// Represent a SQLite prepared statement. Prepared statements execute faster
+	// and are generally safer than a standard execute call as all bound
+	// parameters are escaped properly.
+	//
+	// To create a `SQLITE_STATEMENT`, use `SQLITE.prepare`. Any valid SQL
+	// can be sent to prepare. Further bound values are inserted with
+	// each call to step. ? and ?NNN are supported.
+
+	+ name     := SQLITE_STATEMENT;
+
+	- copyright := "2008, Jeremy Cowgar";
+
+	- comment := "SQLite binding of prepared statements";
+
+	- external := `#include <sqlite3.h>`;
+
+Section Inherit
+
+	- parent_object:OBJECT := OBJECT;
+
+Section Public
+
+	- pointer :POINTER := NULL;
+	// Internal pointer to the "sqlite3_stmt *" statement handle.
+
+Section Public
+	// Create/Reset/Destroy slots
+
+	- set_stmt p:POINTER <-
+	// Set the C sqlite3_stmt* handle for this statement.
+	(
+		pointer := p;
+	);
+
+	- make stmt:POINTER :SELF <-
+	// Clone `SQLITE_STATEMENT` with the given `stmt` as the statement
+	// pointer.
+	(
+		+ result:SELF;
+
+		result := SELF.clone;
+		result.set_stmt stmt;
+		result
+	);
+
+	- finalize <-
+	// Finalize the prepared statement which free's all memory
+	// associated with it. Once finalized, this `SQLITE_STATEMENT`
+	// can no longer be used.
+	(
+		+ stmt:POINTER;
+		stmt := pointer;
+		`sqlite3_finalize(@stmt)`;
+		pointer := NULL;
+	);
+
+	- reset <-
+	// Reset the prepared statement back to it's initial state, ready to be
+	// re-executed. Any SQL statement variables that had values bound to
+	// them using the `bind` slots retain their values. Use `clear_bindings`
+	// to reset the bindings.
+	(
+		+ stmt:POINTER;
+		stmt := pointer;
+		`sqlite3_reset(@stmt)`;
+	);
+
+	- clear_bindings <-
+	// Reset all bound values of the prepared statement to NULL.
+	(
+		+ stmt:POINTER;
+		stmt := pointer;
+		`sqlite3_clear_bindings(@stmt)`;
+	);
+
+Section Public
+	// Movement through the result set.
+
+	- step :INTEGER <-
+	// Evaluate the next (or first) SQL statement in the prepared statement.
+	(
+		+ stmt: POINTER;
+		stmt := pointer;
+		`sqlite3_step(@stmt)`:INTEGER
+	);
+
+	- foreach b:BLOCK <-
+	// Evaluate the prepared statement calling `b` for each row that is
+	// returned by `step`. Warning: When completed, `foreach` does not
+	// automatically call finalize. This is left up to the caller.
+	(
+		{ step = SQLITE.row }.while_do b;
+	);
+
+Section Public
+	// Binding for execute
+
+	- bind col:INTEGER to_integer v:INTEGER <-
+	// Bind the integer value `v` to the column `col`.
+	(
+		+ stmt :POINTER;
+		stmt := pointer;
+		`sqlite3_bind_int(@stmt, @col, @v)`;
+	);
+
+	- bind col:INTEGER to_integer64 v:INTEGER_64 <-
+	// Bind the 64bit integer value `v` to the column `col`.
+	(
+		+ stmt :POINTER;
+		stmt := pointer;
+		`sqlite3_bind_int64(@stmt, @col, @v)`;
+	);
+
+	- bind col:INTEGER to_real v:REAL_64 <-
+	// Bind the real value `v` to the column `col`.
+	(
+		+ stmt :POINTER;
+		stmt := pointer;
+		`sqlite3_bind_double(@stmt, @col, @v)`;
+	);
+
+	- bind col:INTEGER to_string v:ABSTRACT_STRING <-
+	// Bind the string value `v` to the column `col`.
+	(
+		+ stmt    : POINTER;
+		+ a_value : NATIVE_ARRAY[CHARACTER];
+
+		stmt    := pointer;
+		a_value := v.to_external;
+
+		`sqlite3_bind_text(@stmt, @col, @a_value, -1, 0)`;
+	);
+
+	- bind_nul col:INTEGER <-
+	// Bind null to the colum `col`.
+	(
+		+ stmt :POINTER;
+		stmt := pointer;
+		`sqlite3_bind_null(@stmt, @col)`;
+	);
+
+Section Public
+	// Column Values
+
+	- as_integer col:INTEGER :INTEGER <-
+	// Get the value of `col` as an integer.
+	(
+		+ stmt:POINTER;
+		stmt := pointer;
+		`sqlite3_column_int(@stmt, @col)`:INTEGER
+	);
+
+	- as_integer64 col:INTEGER :INTEGER <-
+	// Get the value of `col` as a 64bit integer.
+	(
+		+ stmt:POINTER;
+		stmt := pointer;
+		`sqlite3_column_int64(@stmt, @col)`:INTEGER_64
+	);
+
+	- as_double col:INTEGER :REAL_64 <-
+	// Get the value of `col` as a double.
+	(
+		+ stmt:POINTER;
+		stmt := pointer;
+		`sqlite3_column_double(@stmt, @col)`:REAL_64
+	);
+
+	- as_string col:INTEGER :STRING <-
+	// Get the value of `col` as a string.
+	(
+		+ stmt : POINTER;
+		+ value : NATIVE_ARRAY[CHARACTER];
+		+ result : STRING;
+
+		stmt := pointer;
+		value := `sqlite3_column_text(@stmt, @col)`:NATIVE_ARRAY[CHARACTER];
+
+		result := STRING.clone;
+		result.from_external(value);
+		result
+	);
+
+Section Public
+	// Column Information
+
+	- count :INTEGER <-
+	// Get the number of columns in the prepared statement.
+	(
+		+ stmt:POINTER;
+		`sqlite3_column_count(@stmt)`:INTEGER
+	);
+
+	- type col:INTEGER :INTEGER <-
+	// Get the column type of column `col`.
+	(
+		+ stmt :POINTER;
+		stmt := pointer;
+		`sqlite3_column_type(@stmt, @col)`:INTEGER
+	);
+
+	- declared_type col:INTEGER :STRING <-
+	// Get the declared type of column `col`.
+	(
+		+ stmt:POINTER;
+		+ n_name:NATIVE_ARRAY[CHARACTER];
+		+ result:STRING;
+
+		stmt := POINTER;
+		n_name := `sqlite3_column_decltype(@stmt, @col)`:NATIVE_ARRAY[CHARACTER];
+
+		result := STRING.clone;
+		result.from_external(n_name);
+		result
+	);
+
+	- name col:INTEGER :STRING <-
+	// Get the column name of column `col`.
+	(
+		+ stmt:POINTER;
+		+ n_name:NATIVE_ARRAY[CHARACTER];
+		+ result:STRING;
+
+		stmt := POINTER;
+		n_name := `sqlite3_column_name(@stmt, @col)`:NATIVE_ARRAY[CHARACTER];
+
+		result := STRING.clone;
+		result.from_external(n_name);
+		result
+	);
+
+	- table_name col:INTEGER :STRING <-
+	// Get the table name of column `col`.
+	(
+		+ stmt:POINTER;
+		+ n_name:NATIVE_ARRAY[CHARACTER];
+		+ result:STRING;
+
+		stmt := POINTER;
+		n_name := `sqlite3_column_table_name(@stmt, @col)`:NATIVE_ARRAY[CHARACTER];
+
+		result := STRING.clone;
+		result.from_external(n_name);
+		result
+	);
+
+	- database_name col:INTEGER :STRING <-
+	// Get the database name of column `col`.
+	(
+		+ stmt:POINTER;
+		+ n_name:NATIVE_ARRAY[CHARACTER];
+		+ result:STRING;
+
+		stmt := POINTER;
+		n_name := `sqlite3_column_database_name(@stmt, @col)`:NATIVE_ARRAY[CHARACTER];
+
+		result := STRING.clone;
+		result.from_external(n_name);
+		result
+	);

-- 
Lisaac library sqlite-binding



More information about the Lisaac-commits mailing list