Commits

Greg Slepak committed d38e041

0.6

Comments (0)

Files changed (13)

example-site/dragonfly-api/ObjNL.lsp.html

+<!DOCTYPE HTML PUBLIC "HTML 4.01 Transitional">
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ObjNL.lsp</title>
+
+<link rel="stylesheet" type="text/css" href="newlispdoc.css" />
+</head>
+
+<body style="margin: 20px;" text="#111111" bgcolor="#FFFFFF" 
+			link="#376590" vlink="#551A8B" alink="#ffAA28">
+<blockquote>
+<center><h1>ObjNL.lsp</h1></center>
+<p><a href="index.html">Module index</a></p><br/><br/><br/><h2>Module:&nbsp;ObjNL.lsp</h2><p>Objective newLISP - Real Object Oriented Programming for newLISP</p>
+<b>Version: </b>1.0<br/>
+<b>Author: </b>Greg Slepak<br/>
+<b>Location: </b><a href="http://www.taoeffect.com/newlisp/ObjNL.lsp.txt">http://www.taoeffect.com/newlisp/ObjNL.lsp.txt</a><br/>
+ <h3>Introductory Guide</h3>
+ The <a href="http://www.taoeffect.com/blog/2009/12/introducing-objective-newlisp/">official&nbsp;guide</a>  is highly recommended reading if you are planning on using Objective newLISP.
+ <h3>What is Objective newLISP?</h3>
+ Objective newLISP is a new and exciting way of doing <b>real</b>
+ object oriented programming in newLISP where instances are passed
+ by reference and can easily hold references to other objects while
+ maintaining their own mutable state.
+ <p>It supports most of the object oriented concepts you'll find
+ in other languages. It supports inheritance, interfaces (aka protocols),
+ as well as class and instance variables.</p>
+ <p>Objects are passed <i>by reference</i>, so there's no problem with passing
+ an object through multiple user-defined functions and modifying it.</p>
+ <p>Accessing instance variables no longer requires a function call plus a
+ list traversal. Simply access the symbol directly.</p>
+ <p>Objective newLISP also enhances newLISP by providing convenient and safe
+ macros for deep reference access.</p>
+ <p>With Objective newLISP it is possible to take full advantage of everything
+ object-oriented programming has to offer.</p>
+ <h3>Conventions</h3>
+ There are very few conventions in ObjNL, but there are some:
+ <ul>
+ <li>Classes should be written in camel-case and begin with a capital letter.</li>
+ <li>ObjNL reserves the @ character for itself to prefix symbols of special meaning.
+ You should avoid prefixing your symbols with it if possible.</li>
+ </ul>
+ <h3>Requirements</h3>
+ newLISP 10.1.9 or higher is <b>strongly recommended</b>, but any version after 10.1 should work.
+ <h3>Version history</h3>
+ <b>1.0</b> &bull; initial release
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_ObjNL"></a><h3><font color=#CC0000>ObjNL</font></h3>
+<b>syntax: ObjNL</b><br/>
+ <p><tt>ObjNL</tt> is the root class for Objective newLISP. All other classes ultimately
+ inherit from it. It defines several instance and class variables:</p>
+ <ul>
+ <li><tt>@self</tt> to refer to the current object (be it an instance or class).</li>
+ <li><tt>@self-sym</tt> is the symbol that represents the <tt>@self</tt> context.</li>
+ <li><tt>@class</tt> is the context representing the class this object belongs to.</li>
+ <li><tt>@super</tt> refers to the super-class of this object.</li>
+ <li><tt>@interfaces</tt> a list of interfaces that this object conforms to.</li>
+ <li><tt>@rc</tt> an integer representing the retain count of this object.</li>
+ </ul>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="ObjNL_ObjNL"></a><h3><font color=#CC0000>ObjNL:ObjNL</font></h3>
+<b>syntax: (<font color=#CC0000>ObjNL:ObjNL</font>)</b><br/>
+ <p>The constructor is the default function. It is called by <tt>instantiate</tt>.</p>
+ <p>The default implementation simply returns <tt>true</tt>.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="ObjNL_dealloc"></a><h3><font color=#CC0000>ObjNL:dealloc</font></h3>
+<b>syntax: (<font color=#CC0000>ObjNL:dealloc</font>)</b><br/>
+ <p>Called by <tt>deallocate</tt> to give the object an opportunity to release resources and objects.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="ObjNL_equals"></a><h3><font color=#CC0000>ObjNL:equals</font></h3>
+<b>syntax: (<font color=#CC0000>ObjNL:equals</font> <em>ctx-obj</em>)</b><br/>
+ <p>Provides a method for classes to define what it means for objects to be equal.</p>
+ <p>The default implementation returns <tt>true</tt> if two objects are the same instance.</p>
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_new-class"></a><h3><font color=#CC0000>new-class</font></h3>
+<b>syntax: (<font color=#CC0000>new-class</font> <em>sym-class</em> [<em>ctx-super</em> [<em>list-interfaces</em>]])</b><br/>
+<b>parameter: </b><em>sym-class</em> - The name of the class<br/>
+<b>parameter: </b><em>ctx-super</em> - The superclass, accessible through <tt>@super</tt><br/>
+<b>parameter: </b><em>list-interfaces</em> - Any contexts to "mixin", accessible through <tt>@interfaces</tt><br/>
+<p><b>return: </b>The context of the new class created.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_instantiate"></a><h3><font color=#CC0000>instantiate</font></h3>
+<b>syntax: (<font color=#CC0000>instantiate</font> <em>ctx-class</em> [<em>arg-1</em> ...])</b><br/>
+ <p>Returns a new instance of <em>ctx-class</em> by calling its
+ constructor and passing in any arguments. If the constructor
+ returns nil then the instance is deallocated and nil is returned.</p>
+ <p>The returned object <b>must</b> be deallocated using the <tt>deallocate</tt>
+ function.</p>
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_add-interface"></a><h3><font color=#CC0000>add-interface</font></h3>
+<b>syntax: (<font color=#CC0000>add-interface</font> <em>ctx-iface</em> <em>ctx-obj</em>)</b><br/>
+ <p>Uses the function <tt>new</tt> to add <em>ctx-iface</em> to the object and
+ adds the interface to <em>ctx-obj</em>s <tt>@interfaces</tt>.</p>
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_deallocate"></a><h3><font color=#CC0000>deallocate</font></h3>
+<b>syntax: (<font color=#CC0000>deallocate</font> <em>ctx-obj</em>)</b><br/>
+ <p>Calls the objects <tt>dealloc</tt> method and then <tt>delete</tt>&apos;s the object.</p>
+ <p><b>NOTE:</b> On versions of newLISP prior to 10.1.9 this is a fairly slow
+ operation, make sure to use at least version 10.1.9 with Objective newLISP.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_implements?"></a><h3><font color=#CC0000>implements?</font></h3>
+<b>syntax: (<font color=#CC0000>implements?</font> <em>ctx-interface</em> <em>ctx-obj</em>)</b><br/>
+<p><b>return: </b>true or nil as to whether this <em>ctx-obj</em> implements <em>ctx-interface</em>.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_retain"></a><h3><font color=#CC0000>retain</font></h3>
+<b>syntax: (<font color=#CC0000>retain</font> <em>ctx-obj</em>)</b><br/>
+ <p>Increment's <em>ctx-obj</em>&apos;s retain count and returns the object.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_release"></a><h3><font color=#CC0000>release</font></h3>
+<b>syntax: (<font color=#CC0000>release</font> <em>ctx-obj</em>)</b><br/>
+ <p>Decrement's <em>ctx-obj</em>&apos;s retain count. Deallocates the object if the retain count hits zero.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_autorelease"></a><h3><font color=#CC0000>autorelease</font></h3>
+<b>syntax: (<font color=#CC0000>autorelease</font> <em>ctx-obj</em>)</b><br/>
+ <p>Adds <em>ctx-obj</em> to the current <tt>MAIN:@autorelease</tt> pool and returns the object.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_push-autorelease-pool"></a><h3><font color=#CC0000>push-autorelease-pool</font></h3>
+<b>syntax: (<font color=#CC0000>push-autorelease-pool</font>)</b><br/>
+ <p>Pushes a new autorelease pool onto the <tt>MAIN:@autorelease</tt> stack.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_pop-autorelease-pool"></a><h3><font color=#CC0000>pop-autorelease-pool</font></h3>
+<b>syntax: (<font color=#CC0000>pop-autorelease-pool</font>)</b><br/>
+ <p>Pops the current <tt>MAIN:@autorelease</tt> pool and releases the objects in it.</p>
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_."></a><h3><font color=#CC0000>.</font></h3>
+<b>syntax: (<font color=#CC0000>.</font> <em>obj</em> <em>field-1</em> [<em>field-2</em> [<em>field-n</em>]])</b><br/>
+ <p>The dot macro is used for "deep value access":</p>
+ <b>example:</b>
+ <pre>
+ (new-class 'Foo)
+ (new-class 'Bar)
+ (context Bar)
+ (define (Bar:Bar f)
+ 	(setf foo f)
+ 	true ; -> do not deallocate us if 'f' is nil
+ )
+ (context Foo)
+ (define (Foo:Foo b)
+ 	(setf bar b)
+ 	true ; -> do not deallocate us if 'b' is nil
+ )
+ (context MAIN)
+ (setf f (instantiate Foo (instantiate Bar)))
+ (set (.& f bar foo) f) ; => Foo#1
+ (. f bar foo bar)      ; => Bar#1</pre>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_.&"></a><h3><font color=#CC0000>.&</font></h3>
+<b>syntax: (<font color=#CC0000>.&</font> <em>obj</em> <em>field-1</em> [<em>field-2</em> [<em>field-n</em>]])</b><br/>
+ <p>The dot-reference macro is similar to the dot macro, except it returns the
+ context-qualified symbol for the final field instead of its value ("deep symbol access").
+ This allows you to combine it with <tt>set</tt>.</p>
+<b>see: </b>'.' macro for example usage.<br/>
+
+
+<br/><br/><center>- &part; -</center><br/>
+<center><font face='Arial' size='-2' color='#444444'>
+generated with <a href="http://newlisp.org">newLISP</a>&nbsp;
+and <a href="http://newlisp.org/newLISPdoc.html">newLISPdoc</a>
+</font></center>
+</blockquote>
+</body>
+</html>

example-site/dragonfly-api/database.lsp.html

+<!DOCTYPE HTML PUBLIC "HTML 4.01 Transitional">
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>database.lsp</title>
+
+<link rel="stylesheet" type="text/css" href="newlispdoc.css" />
+</head>
+
+<body style="margin: 20px;" text="#111111" bgcolor="#FFFFFF" 
+			link="#376590" vlink="#551A8B" alink="#ffAA28">
+<blockquote>
+<center><h1>database.lsp</h1></center>
+<p><a href="index.html">Module index</a></p><br/><br/><br/><h2>Module:&nbsp;DF.DB, DF.SQL, DF.BLOB</h2><p>Generic database access interface for <a href="http://www.rundragonfly.com">Dragonfly</a> using Objective newLISP</p>
+<b>Version: </b>1.1<br/>
+<b>Author: </b>Greg Slepak<br/>
+<b>Location: </b><a href="http://www.taoeffect.com/newlisp/database.lsp.txt">http://www.taoeffect.com/newlisp/database.lsp.txt</a><br/>
+ <p>The purpose of this module is to standardize the interface to
+ access databases. This will allow you, for the most part, to write your code once
+ and easily switch the type of database that you're using.</p>
+ <p>To accomplish this, the interface introduces three Objective newLISP classes:
+ <tt>DF.DB</tt>, <tt>DF.SQL</tt>, and <tt>DF.BLOB</tt>.</p>
+ <h3>DF.DB</h3>
+ A <tt>DF.DB</tt> object represents a database connection. Using it you connect to
+ the database and execute SQL queries.
+ <h3>DF.SQL</h3>
+ A <tt>DF.SQL</tt> object is a wrapper around an SQL statement, is retrieved through one of
+ two functions: <tt>DF.DB:execute-query</tt> and the lower-level <tt>DF.DB:preprare-sql</tt>.
+ <p>It is used to retrieve rows from the result set of a query one-by-one.</p>
+ <h3>DF.BLOB</h3>
+ <tt>DF.BLOB</tt> is used to insert and retrieve (possibly large) binary data into databases.
+ It is needed for two reasons:
+ <ol>
+ <li>newLISP uses strings to buffer and store binary data, and that's already used to store text.</li>
+ <li>BLOBs can be very large, so by storing them in a context we avoid excessive copying.</li>
+ </ol>
+ <p>Unlike the other two classes, <tt>DF.BLOB</tt> provides a basic working implementation for <tt>DF.SQL</tt> subclasses
+ to use. You may of course subclass it if your database requires additional functionality. It requires
+ special usage considerations, see its documentation below.</p>
+ <h3>Example</h3>
+ <pre>
+ (push-autorelease-pool) ; we<tt>re going to be using DF.BLOB</tt>s.
+ (setf db (instantiate Sqlite3 ":memory:"))
+ (if-not db (throw-error "couldn't open db"))
+ (db:execute-update "CREATE TABLE fish (id INTEGER PRIMARY KEY, name TEXT, weight REAL, blah BLOB)")
+ (db:execute-update "INSERT INTO fish (name,weight) VALUES (?,?)" '("flipper" 234.123))
+ (db:execute-update "INSERT INTO fish (name,weight) VALUES (?1,?2)" '(("?1" "catfish") ("?2" 100.3)))
+ (db:execute-update "INSERT INTO fish (blah) VALUES (?)" (list (DF.BLOB (dup "\000" 10))))
+ (db:execute-update "INSERT INTO fish (blah) VALUES (:cat)" (list (list ":cat" (DF.BLOB (dup "\000" 10)))))
+ (setf sql (db:execute-query "SELECT * FROM fish"))
+ (do-while (list? row)
+     (push-autorelease-pool) ; "in case" we end up fetching a lot of large blobs
+     (setf row (sql:next-row))
+     (println "row: " row)
+     (pop-autorelease-pool)
+ )
+ (deallocate sql)
+ (deallocate db)
+ (pop-autorelease-pool) ; deallocate the blobs we created</pre>
+ <h3>Requirements</h3>
+ <ul>
+ <li>Dragonfly newLISP Web Framework (see note below)</li>
+ <li>newLISP 10.1.9 or higher is <b>strongly recommended</b>, but any version after 10.1 should work.</li>
+ <li>Objective newLISP 1.0</li>
+ <li>Libraries for a supported database</li>
+ </ul><br/>
+ <a href="http://www.rundragonfly.com">Dragonfly</a> is only required for its logging functions. You can easily implement your own
+ versions of <tt>DF:log-err</tt>, <tt>DF:log-debug</tt>, and the other functions found in Dragonfly&apos;s <tt>log.lsp</tt>.
+ <h3>Version history</h3>
+ <b>1.1</b> &bull; <tt>DF.BLOB</tt> added<br/>
+ <b>1.0</b> &bull; initial release
+
+
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_DF.DB"></a><h3><font color=#CC0000>DF.DB</font></h3>
+<b>syntax: DF.DB</b><br/>
+ <p>Represents a database connection. You create a DF.DB object
+ like so:</p>
+ <pre>(instantiate <em>DF.DB-Subclass</em> [<em>connection</em> [<em>args...</em>]])</pre>
+ <p>What type should be represented by <em>connection</em> is undefined, but
+ it&apos;s recommended that subclasses use strings. If <em>connection</em> is specified
+ the a connected instance must be returned (or <tt>nil</tt> upon failure).</p>
+ <p>The possibly optional <em>args...</em> are specific to which subclass you're using. See its
+ corresponding documentation.</p>
+ <p>Instances must have code in their <tt>dealloc</tt> method so that they can properly cleanup their resources
+ (e.g. shutdown connection) if deallocated with <tt>deallocate</tt>.</p>
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_open"></a><h3><font color=#CC0000>DF.DB:open</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:open</font> <em>connection</em>)</b><br/>
+ <p>Returns <tt>true</tt> if the connection was opened successfully, <tt>nil</tt>
+ if there was an error opening the connection, or throws an exception
+ if already connected.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_close"></a><h3><font color=#CC0000>DF.DB:close</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:close</font>)</b><br/>
+ <p>Returns <tt>true</tt> if the connection was closed successfully or was
+ already closed, or <tt>nil</tt> if there was an error closing the connection.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_prepare-sql"></a><h3><font color=#CC0000>DF.DB:prepare-sql</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:prepare-sql</font> <em>str-sql</em>)</b><br/>
+<b>parameter: </b><em>str-sql</em> - A single SQL statement. Does not need to end in ';'<br/>
+ <p>Returns a <tt>DF.SQL</tt> object upon success, <tt>nil</tt> on failure, or throws
+ an exception if not connected.</p>
+ <p><b>important:</b> If your SQL statement contains placeholders (to be
+ bound later using <tt>DF.SQL:bind-params</tt>) you may not mix and match placeholder styles!
+ Pick one placeholder style and stick with it for the entire statement.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_execute-update"></a><h3><font color=#CC0000>DF.DB:execute-update</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:execute-update</font> <em>str-sql</em> [<em>list-params</em>])</b><br/>
+<b>parameter: </b><em>str-sql</em> - A single SQL statement. Does not need to end in ';'<br/>
+<b>parameter: </b><em>list-params</em> - A list of parameters to bind to a parameterized query<br/>
+ <p>Same as <tt>DF.DB:execute-query</tt> but returns <tt>true</tt> instead of a <tt>DF.SQL</tt> object upon success.
+ Useful for SQL such as "UPDATE" and "INSERT".</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_execute-query"></a><h3><font color=#CC0000>DF.DB:execute-query</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:execute-query</font> <em>str-sql</em> [<em>list-params</em>])</b><br/>
+<b>parameter: </b><em>str-sql</em> - A single SQL statement. Does not need to end in ';'<br/>
+<b>parameter: </b><em>list-params</em> - A list of parameters to bind to a parameterized query<br/>
+ <p>A short-hand for <tt>DF.DB:prepare-sql</tt> and <tt>DF.SQL:bind-params</tt>. Returns
+ a <tt>DF.SQL</tt> object upon success, <tt>nil</tt> on failure, or throws an exception if
+ not connected.</p>
+ <p><b>see:</b> documentation for <tt>DF.SQL:bind-params</tt> for more info on <em>list-params</em>.
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_rows-for-query"></a><h3><font color=#CC0000>DF.DB:rows-for-query</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:rows-for-query</font> <em>str-sql</em> [<em>list-params</em>])</b><br/>
+ <p>Same as <tt>DF.DB:execute-query</tt> but retrieves all of the rows and returns them as a list of results.</p>
+ <p><b>important:</b> If any columns contain BLOB types, you <b><i>must</i></b> have
+ an autorelease pool allocated prior to calling this function!</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_rowid"></a><h3><font color=#CC0000>DF.DB:rowid</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:rowid</font>)</b><br/>
+ <p>Returns the row id for the last row that was inserted or throws an
+ exception if not connected.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_changes"></a><h3><font color=#CC0000>DF.DB:changes</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:changes</font>)</b><br/>
+ <p>Returns how many rows were affected by the last INSERT/UPDATE, or throws
+ an exception of not connected</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_version"></a><h3><font color=#CC0000>DF.DB:version</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:version</font>)</b><br/>
+ <p>Returns the version number of the database library being used as an integer.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_table-exists?"></a><h3><font color=#CC0000>DF.DB:table-exists?</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:table-exists?</font> <em>table-name</em>)</b><br/>
+ <p>Returns nil or non-nil depending on whether the table named <tt>table-name</tt> exists,
+ or throws an exception if not connected.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_connected?"></a><h3><font color=#CC0000>DF.DB:connected?</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:connected?</font>)</b><br/>
+<p><b>return: </b>nil or non-nil depending on whether this <tt>DF.DB</tt> object has an active connection.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.DB_last-error"></a><h3><font color=#CC0000>DF.DB:last-error</font></h3>
+<b>syntax: (<font color=#CC0000>DF.DB:last-error</font>)</b><br/>
+<p><b>return: </b>a list of two elements: the most recent error code and a description string.</p>
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_DF.SQL"></a><h3><font color=#CC0000>DF.SQL</font></h3>
+<b>syntax: DF.SQL</b><br/>
+ <p>Represents a prepared statement. It is used to bind values to a statement's parameters
+ and retrieve the results of a query.</p>
+ <p>You do not create a DF.SQL instance yourself but obtain one through <tt>DF.DB:prepare-sql</tt>.
+ However, if you've obtained an instance then you are responsible for freeing its memory
+ and closing its connection when you're finished with it.</p>
+ <p>Subclasses should make sure that their <tt>dealloc</tt> method calls <tt>DF.SQL:close</tt> so that
+ statements can be freed and closed in one function call using <tt>deallocate</tt>.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.SQL_bind-params"></a><h3><font color=#CC0000>DF.SQL:bind-params</font></h3>
+<b>syntax: (<font color=#CC0000>DF.SQL:bind-params</font> <em>list-params</em>)</b><br/>
+ <p>Binds the placeholders of this SQL statement to the values in <em>list-params</em>.</p>
+ <p><em>list-params</em> may be simply a list of values, or an association list of key/value
+ pairs, depending on the placeholder pattern used in the SQL. Placeholder styles
+ <b>may not</b> be mixed per SQL statement.</p>
+ <p>Values may be any of newLISP's primitives. To specify a BLOB wrap your string
+ in a <tt>DF.BLOB</tt>:</p>
+ <b>example:</b>
+ <pre>
+ ; "weight" is a REAL and "blah" is a BLOB
+ (push-autorelease-pool) ; create our autorelease pool since we're using DF.BLOB
+ (setf sql (db:prepare-sql "INSERT INTO fish (weight,blah) VALUES (?,?)"))
+ (sql:bind-params (list 1043.3 (DF.BLOB (dup "\000" 5))))
+ (println (sql:next-row))
+ (deallocate sql)
+ (pop-autorelease-pool)
+ </pre>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.SQL_next-row"></a><h3><font color=#CC0000>DF.SQL:next-row</font></h3>
+<b>syntax: (<font color=#CC0000>DF.SQL:next-row</font>)</b><br/>
+ <p>Returns a row as a list from the result set of a statement, <tt>true</tt> if
+ there are no more rows to return, or <tt>nil</tt> if there was an error.</p>
+ <b>example:</b>
+ <pre> (push-autorelease-pool) ; only necessary if there's a BLOB column
+ (while (list? (setf row (sql:next-row)))
+ 	(println "row: " row)
+ )
+ (pop-autorelease-pool) ; free any blobs</pre>
+ <p><b>important:</b> If any columns contain BLOB types, you <b><i>must</i></b> have
+ an autorelease pool allocated prior to calling this function!</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.SQL_reset"></a><h3><font color=#CC0000>DF.SQL:reset</font></h3>
+<b>syntax: (<font color=#CC0000>DF.SQL:reset</font>)</b><br/>
+ <p>Resets the statement so that it can be re-used without preparing another
+ statement (which is more efficient). After reseting a statement you typically
+ use <tt>DF.SQL:bind-params</tt> to bind new values and then <tt>DF.SQL:next-row</tt>.</p>
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.SQL_close"></a><h3><font color=#CC0000>DF.SQL:close</font></h3>
+<b>syntax: (<font color=#CC0000>DF.SQL:close</font>)</b><br/>
+ <p>Releases the resources used by the SQL statement represented by this object.
+ You cannot use it anymore after calling this method, the only thing left to do
+ is to <tt>deallocate</tt> it, and since sublasses of <tt>DF.SQL</tt> must call <tt>close</tt> in
+ their <tt>dealloc</tt> methods, it&apos;s often simpler to call <tt>deallocate</tt> on the object instead.</p>
+ <p>Returns <tt>true</tt> upon success, <tt>nil</tt> on failure or if already closed.</p>
+
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="DF.BLOB_DF.BLOB"></a><h3><font color=#CC0000>DF.BLOB:DF.BLOB</font></h3>
+<b>syntax: (<font color=#CC0000>DF.BLOB:DF.BLOB</font> <em>str-blob</em>)</b><br/>
+ <p>An object wrapper around a blob of data represented by <em>str-blob</em>, used
+ for efficient passing of possibly large binary data.</p>
+ <p>Unlike most other <tt>ObjNL</tt> classes, you typically create an instance
+ by simply calling its constructor instead of calling <tt>instantiate</tt> yourself.
+ It will then <tt>instantiate</tt> and <tt>autorelease</tt> a <tt>DF.BLOB</tt> instance containing the data
+ in <tt>DF.BLOB:blob</tt>.</p>
+ <p><b>important:</b> An autorelease pool <b>must</b> be in place when using the
+ constructor to instantiate a blob!</p>
+ <p><b>see:</b> the introduction to this document for example usage.</p>
+
+
+<br/><br/><center>- &part; -</center><br/>
+<center><font face='Arial' size='-2' color='#444444'>
+generated with <a href="http://newlisp.org">newLISP</a>&nbsp;
+and <a href="http://newlisp.org/newLISPdoc.html">newLISPdoc</a>
+</font></center>
+</blockquote>
+</body>
+</html>

example-site/dragonfly-api/database_sqlite3.lsp.html

+<!DOCTYPE HTML PUBLIC "HTML 4.01 Transitional">
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>database_sqlite3.lsp</title>
+
+<link rel="stylesheet" type="text/css" href="newlispdoc.css" />
+</head>
+
+<body style="margin: 20px;" text="#111111" bgcolor="#FFFFFF" 
+			link="#376590" vlink="#551A8B" alink="#ffAA28">
+<blockquote>
+<center><h1>database_sqlite3.lsp</h1></center>
+<p><a href="index.html">Module index</a></p><br/><br/><br/><h2>Module:&nbsp;Sqlite3</h2><p>SQLite3 subclass of DF.DB. Only lists Sqlite3 specific functions.</p>
+<b>Version: </b>1.1<br/>
+<b>Author: </b>Greg Slepak <br/>
+<b>Location: </b><a href="http://www.taoeffect.com/newlisp/database_sqlite3.lsp.txt">http://www.taoeffect.com/newlisp/database_sqlite3.lsp.txt</a><br/>
+ <h3>Features not found in newLISP's sqlite3.lsp:</h3>
+ <ul>
+ <li>Multiple connections</li>
+ <li>Multiple active SQL statements</li>
+ <li>Supports reuse of SQL statements through parameter rebinding</li>
+ <li>Supports BLOB data-type as per <tt>DF.DB</tt> and <tt>DF.BLOB</tt> specification</li>
+ <li>Conforms to generic <tt>DF.DB</tt> interface</li>
+ <li>Grabs integers directly through 64-bit function</li>
+ <li>Can go through results row-by-row</li>
+ <li>Allows specification of custom sqlite3 library page with <tt>SQLITE3_LIBRARY_PATH</tt></li>
+ <li>Uses the latest Sqlite3 library functions if they are available</li>
+ <li>Better error handling</li>
+ </ul>
+ <h3>Requirements</h3>
+ See module <a href="http://www.taoeffect.com/newlisp/database.lsp.html">DF.DB</a> for requirements.
+ <h3>Version history</h3>
+ <b>1.1</b> &bull; support for <tt>DF.BLOB</tt><br/>
+ <b>1.0</b> &bull; initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_Sqlite3"></a><h3><font color=#CC0000>Sqlite3</font></h3>
+<b>syntax: Sqlite3</b><br/>
+ <p>Represents a connection to an SQLite3 database. Create one like so:</p>
+ <pre>(instantiate Sqlite3 [<em>str-filepath</em> [<em>flags</em> [<em>vfs-module</em>]]])</pre>
+ <p>If <em>str-filepath</em> is specified a connected instance will be returned or <tt>nil</tt>
+ upon failure to connect. If they are not specified then an unconnected instance
+ will be returned.</p>
+ <p><b>see:</b> documentation for <tt>Sqlite3:open</tt> for an explanation of the parameters.</p>
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Sqlite3_open"></a><h3><font color=#CC0000>Sqlite3:open</font></h3>
+<b>syntax: (<font color=#CC0000>Sqlite3:open</font> <em>str-filepath</em> [<em>flags</em> [<em>vfs-module</em>]])</b><br/>
+ <p><em>str-filepath</em> specifies the path to the sqlite3 database, but it can also be
+ ":memory:" to indicate an in-memory database.</p>
+ <p><em>flags</em> and <em>vfs-module</em> are optional parameters as defined in the sqlite
+ reference <a href="http://www.sqlite.org/c3ref/open.html">documentation</a> for
+ <tt>sqlite3_open_v2</tt>. Your installation of sqlite3 may need to be updated for this to be available.</p>
+ <p>For return values see <tt>DF.DB:open</tt>.</p>
+
+
+
+
+
+
+
+
+
+
+
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Sqlite3_set-timeout"></a><h3><font color=#CC0000>Sqlite3:set-timeout</font></h3>
+<b>syntax: (<font color=#CC0000>Sqlite3:set-timeout</font> <em>int-ms</em>)</b><br/>
+ <p>Sets the sqlite3's busy timeout for this connection in milliseconds.</p>
+ <p>By default the timeout is set to 30 seconds.</p>
+<p><b>return: </b>nil or non-nil on success</p>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<br/><br/><center>- &part; -</center><br/>
+<center><font face='Arial' size='-2' color='#444444'>
+generated with <a href="http://newlisp.org">newLISP</a>&nbsp;
+and <a href="http://newlisp.org/newLISPdoc.html">newLISPdoc</a>
+</font></center>
+</blockquote>
+</body>
+</html>

example-site/dragonfly-api/gendocs

+#!/bin/sh
+
+# place ObjNL.lsp at the bottom
+newlispdoc ../dragonfly-framework/dragonfly.lsp `find -E ../dragonfly-framework/lib -regex "[./a-z_-]+lsp" | xargs` ../dragonfly-framework/lib/ObjNL.lsp
+
+# we link to DF.DB etc from the guide on included plugins

example-site/dragonfly-api/index.html

 <p></p>
 <a href="response.lsp.html#Response_status">status</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_header">header</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_cookie">cookie</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_send-headers">send-headers</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_redirect">redirect</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_send-headers-with-status">send-headers-with-status</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_content-type">content-type</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_extension->type">extension->type</a>&nbsp; &nbsp; <a href="utils.lsp.html"><br/><br/><h2>Module:&nbsp;utils.lsp</h2></a>
 <p></p>
-<a href="utils.lsp.html#_regex-captcha">regex-captcha</a>&nbsp; &nbsp; <a href="utils.lsp.html#_load-files-in-dir">load-files-in-dir</a>&nbsp; &nbsp; <a href="utils.lsp.html#_into-ctx-assoc">into-ctx-assoc</a>&nbsp; &nbsp; 
+<a href="utils.lsp.html#_regex-captcha">regex-captcha</a>&nbsp; &nbsp; <a href="utils.lsp.html#_load-files-in-dir">load-files-in-dir</a>&nbsp; &nbsp; <a href="utils.lsp.html#_into-ctx-assoc">into-ctx-assoc</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html"><br/><br/><h2>Module:&nbsp;ObjNL.lsp</h2></a>
+<p>Objective newLISP - Real Object Oriented Programming for newLISP</p>
+<a href="ObjNL.lsp.html#_ObjNL">ObjNL</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#ObjNL_ObjNL">ObjNL</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#ObjNL_dealloc">dealloc</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#ObjNL_equals">equals</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_new-class">new-class</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_instantiate">instantiate</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_add-interface">add-interface</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_deallocate">deallocate</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_implements?">implements?</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_retain">retain</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_release">release</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_autorelease">autorelease</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_push-autorelease-pool">push-autorelease-pool</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_pop-autorelease-pool">pop-autorelease-pool</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_.">.</a>&nbsp; &nbsp; <a href="ObjNL.lsp.html#_.&">.&</a>&nbsp; &nbsp; 
 <br/><br/><center>- &part; -</center><br/>
 <center><font face='Arial' size='-2' color='#444444'>
 generated with <a href="http://newlisp.org">newLISP</a>&nbsp;

example-site/dragonfly-api/request.lsp.html

 
 
 
+
 <br/><br/><center>- &part; -</center><br/>
 <center><font face='Arial' size='-2' color='#444444'>
 generated with <a href="http://newlisp.org">newLISP</a>&nbsp;

example-site/dragonfly-framework/lib/ObjNL.lsp

+;; @module ObjNL.lsp
+;; @description Objective newLISP - Real Object Oriented Programming for newLISP
+;; @version 1.0
+;; @author Greg Slepak
+;; @location http://www.taoeffect.com/newlisp/ObjNL.lsp.txt
+;; <h3>Introductory Guide</h3>
+;; The @link http://www.taoeffect.com/blog/2009/12/introducing-objective-newlisp/ official&nbsp;guide
+;; is highly recommended reading if you are planning on using Objective newLISP.
+;; <h3>What is Objective newLISP?</h3>
+;; Objective newLISP is a new and exciting way of doing <b>real</b>
+;; object oriented programming in newLISP where instances are passed
+;; by reference and can easily hold references to other objects while
+;; maintaining their own mutable state.
+;; <p>It supports most of the object oriented concepts you'll find
+;; in other languages. It supports inheritance, interfaces (aka protocols),
+;; as well as class and instance variables.</p>
+;; <p>Objects are passed <i>by reference</i>, so there's no problem with passing
+;; an object through multiple user-defined functions and modifying it.</p>
+;; <p>Accessing instance variables no longer requires a function call plus a
+;; list traversal. Simply access the symbol directly.</p>
+;; <p>Objective newLISP also enhances newLISP by providing convenient and safe
+;; macros for deep reference access.</p>
+;; <p>With Objective newLISP it is possible to take full advantage of everything
+;; object-oriented programming has to offer.</p>
+;; <h3>Conventions</h3>
+;; There are very few conventions in ObjNL, but there are some:
+;; <ul>
+;; <li>Classes should be written in camel-case and begin with a capital letter.</li>
+;; <li>ObjNL reserves the @ character for itself to prefix symbols of special meaning.
+;; You should avoid prefixing your symbols with it if possible.</li>
+;; </ul>
+;; <h3>Requirements</h3>
+;; newLISP 10.1.9 or higher is <b>strongly recommended</b>, but any version after 10.1 should work.
+;; <h3>Version history</h3>
+;; <b>1.0</b> &bull; initial release
+
+;; @syntax ObjNL
+;; <p>'ObjNL' is the root class for Objective newLISP. All other classes ultimately
+;; inherit from it. It defines several instance and class variables:</p>
+;; <ul>
+;; <li>'@self' to refer to the current object (be it an instance or class).</li>
+;; <li>'@self-sym' is the symbol that represents the '@self' context.</li>
+;; <li>'@class' is the context representing the class this object belongs to.</li>
+;; <li>'@super' refers to the super-class of this object.</li>
+;; <li>'@interfaces' a list of interfaces that this object conforms to.</li>
+;; <li>'@rc' an integer representing the retain count of this object.</li>
+;; </ul>
+(set 'ObjNL:@super nil                 ; ObjNL has no super class
+     'ObjNL:@self ObjNL                ; similar to ObjC, can be instance or class
+     'ObjNL:@self-sym 'ObjNL           ; symbol referencing name of this context
+     'ObjNL:@class ObjNL               ; always refers to class, never instance
+     'ObjNL:@interfaces (list ObjNL)   ; ObjNL implements ObjNL
+     'ObjNL:@rc 1                      ; the object's retain (or 'reference') count
+)
+
+(context ObjNL)
+;; @syntax (ObjNL:ObjNL)
+;; <p>The constructor is the default function. It is called by 'instantiate'.</p>
+;; <p>The default implementation simply returns 'true'.</p>
+(define (ObjNL:ObjNL) true)
+
+;; @syntax (ObjNL:dealloc)
+;; <p>Called by 'deallocate' to give the object an opportunity to release resources and objects.</p>
+(define (ObjNL:dealloc))
+
+;; @syntax (ObjNL:equals <ctx-obj>)
+;; <p>Provides a method for classes to define what it means for objects to be equal.</p>
+;; <p>The default implementation returns 'true' if two objects are the same instance.</p>
+(define (ObjNL:equals obj) (= obj @self))
+(context MAIN)
+
+; it's possible to even implement reference counting :-p
+
+;; @syntax (new-class <sym-class> [<ctx-super> [<list-interfaces>]])
+;; @param <sym-class> The name of the class
+;; @param <ctx-super> The superclass, accessible through '@super'
+;; @param <list-interfaces> Any contexts to "mixin", accessible through '@interfaces'
+;; @return The context of the new class created.
+(define (new-class sym-class (super ObjNL) (interfaces '()) , class)
+	(set 'class            (new super sym-class)
+	     'class:@super     super
+	     'class:@class     class
+	     'class:@self      class
+	     'class:@self-sym  sym-class
+	)
+	; NOTE: newLISP Bug? Why does pushing to the back result in odd behavior?
+	; (push class class:@interfaces -1)
+	(push class class:@interfaces)
+	(dolist (iface interfaces)
+		(setf iface (eval iface))
+		(new  iface sym-class)
+		(push iface class:@interfaces)
+	)
+	class
+)
+
+;; @syntax (instantiate <ctx-class> [<arg-1> ...])
+;; <p>Returns a new instance of <ctx-class> by calling its
+;; constructor and passing in any arguments. If the constructor
+;; returns nil then the instance is deallocated and nil is returned.</p>
+;; <p>The returned object <b>must</b> be deallocated using the 'deallocate'
+;; function.</p>
+(define (instantiate class)
+	(letn (	obj-sym	(sym (string class "#" (inc class:@instance-counter)))
+			obj		(new class obj-sym)
+		)
+		; set these prior to calling the constructor
+		(set 'obj:@self obj 'obj:@self-sym obj-sym)
+		(if (apply obj $args)
+			obj
+			(begin (deallocate obj) nil)
+		)
+	)
+)
+;; @syntax (add-interface <ctx-iface> <ctx-obj>)
+;; <p>Uses the function 'new' to add <ctx-iface> to the object and
+;; adds the interface to <ctx-obj>s '@interfaces'.</p>
+(define (add-interface iface obj)
+	(new iface obj:@self-sym)
+	(push iface obj:@interfaces)
+)
+;; @syntax (deallocate <ctx-obj>)
+;; <p>Calls the objects 'dealloc' method and then 'delete'&apos;s the object.</p>
+;; <p><b>NOTE:</b> On versions of newLISP prior to 10.1.9 this is a fairly slow
+;; operation, make sure to use at least version 10.1.9 with Objective newLISP.</p>
+(define (deallocate obj)
+	(obj:dealloc)
+	(let (obj-sym obj:@self-sym)
+		(delete obj-sym nil) ; delete the context
+		(delete obj-sym nil) ; delete the symbol in MAIN
+	)
+)
+
+;; @syntax (implements? <ctx-interface> <ctx-obj>)
+;; @return true or nil as to whether this <ctx-obj> implements <ctx-interface>.
+(define (implements? iface obj)
+	(not (nil? (find iface obj:@interfaces)))
+)
+
+;; @syntax (retain <ctx-obj>)
+;; <p>Increment's <ctx-obj>&apos;s retain count and returns the object.</p>
+(define (retain obj)
+	(inc obj:@rc)
+	obj
+)
+
+;; @syntax (release <ctx-obj>)
+;; <p>Decrement's <ctx-obj>&apos;s retain count. Deallocates the object if the retain count hits zero.</p>
+(define (release obj)
+	(when (zero? (dec obj:@rc))
+		(deallocate obj)
+	)
+)
+
+;; @syntax (autorelease <ctx-obj>)
+;; <p>Adds <ctx-obj> to the current 'MAIN:@autorelease' pool and returns the object.</p>
+(define (autorelease obj)
+	(push obj (first @autorelease))
+	obj
+)
+
+;; @syntax (push-autorelease-pool)
+;; <p>Pushes a new autorelease pool onto the 'MAIN:@autorelease' stack.</p>
+(define (push-autorelease-pool)
+	(push '() @autorelease)
+)
+
+;; @syntax (pop-autorelease-pool)
+;; <p>Pops the current 'MAIN:@autorelease' pool and releases the objects in it.</p>
+(define (pop-autorelease-pool , obj)
+	(dolist (obj (pop @autorelease))
+		(release obj)
+	)
+)
+
+(global 'new-class 'instantiate 'deallocate 'implements?
+	'retain 'release 'autorelease 'push-autorelease-pool 'pop-autorelease-pool '@autorelease)
+
+;; @syntax (. <obj> <field-1> [<field-2> [<field-n>]])
+;; <p>The dot macro is used for "deep value access":</p>
+;; <b>example:</b>
+;; <pre>
+;; (new-class 'Foo)
+;; (new-class 'Bar)
+;; (context Bar)
+;; (define (Bar:Bar f)
+;; 	(setf foo f)
+;; 	true ; -> do not deallocate us if 'f' is nil
+;; )
+;; (context Foo)
+;; (define (Foo:Foo b)
+;; 	(setf bar b)
+;; 	true ; -> do not deallocate us if 'b' is nil
+;; )
+;; (context MAIN)
+;; (setf f (instantiate Foo (instantiate Bar)))
+;; (set (.& f bar foo) f) ; => Foo#1
+;; (. f bar foo bar)      ; => Bar#1</pre>
+(context '.)
+(define-macro (.:. obj)
+	(doargs (field)
+		(setf obj (eval (sym field (eval obj) nil)))
+	)
+)
+
+;; @syntax (.& <obj> <field-1> [<field-2> [<field-n>]])
+;; <p>The dot-reference macro is similar to the dot macro, except it returns the
+;; context-qualified symbol for the final field instead of its value ("deep symbol access").
+;; This allows you to combine it with 'set'.</p>
+;; @see '.' macro for example usage.
+(context '.&)
+(define-macro (.&:.& obj)
+	(doargs (field)
+		(setf obj (sym field (eval obj)))
+	)
+)
+
+(context MAIN)

example-site/dragonfly-framework/lib/utils.lsp

 		(dolist (x assoc-list) (ctx (x 0) (x 1))) ; here dolist is slightly faster than map
 	)
 	
-	
 	; these functions should be global (define-subclass should not)
 	(global 'load-files-in-dir 'regex-captcha 'load-once 'into-ctx-assoc)
 	
 	(constant 'print Dragonfly:print)
 	(constant (global 'sys-println) println)
 	(constant 'println Dragonfly:println)
+	
+	; some other useful globals (primarily used by database.lsp)
+	(constant (global 'NEWLISP64) (not (zero? (& (sys-info -1) 256))))
+	; cache the function for getting a pointer
+	(constant (global 'get-ptr) (if NEWLISP64 get-long get-int))
+	; used to indicate that a method *must* be overwritten
+	(constant (global 'throw-not-implemented) (fn()(throw-error "not defined by subclass!")))
 )
 

example-site/dragonfly-framework/plugins-inactive/db/database.lsp

+;; @module DF.DB, DF.SQL, DF.BLOB
+;; @description Generic database access interface for <a href="http://www.rundragonfly.com">Dragonfly</a> using Objective newLISP
+;; @version 1.1
+;; @author Greg Slepak
+;; @location http://www.taoeffect.com/newlisp/database.lsp.txt
+;; <p>The purpose of this module is to standardize the interface to
+;; access databases. This will allow you, for the most part, to write your code once
+;; and easily switch the type of database that you're using.</p>
+;; <p>To accomplish this, the interface introduces three Objective newLISP classes:
+;; 'DF.DB', 'DF.SQL', and 'DF.BLOB'.</p>
+;; <h3>DF.DB</h3>
+;; A 'DF.DB' object represents a database connection. Using it you connect to
+;; the database and execute SQL queries.
+;; <h3>DF.SQL</h3>
+;; A 'DF.SQL' object is a wrapper around an SQL statement, is retrieved through one of
+;; two functions: 'DF.DB:execute-query' and the lower-level 'DF.DB:preprare-sql'.
+;; <p>It is used to retrieve rows from the result set of a query one-by-one.</p>
+;; <h3>DF.BLOB</h3>
+;; 'DF.BLOB' is used to insert and retrieve (possibly large) binary data into databases.
+;; It is needed for two reasons:
+;; <ol>
+;; <li>newLISP uses strings to buffer and store binary data, and that's already used to store text.</li>
+;; <li>BLOBs can be very large, so by storing them in a context we avoid excessive copying.</li>
+;; </ol>
+;; <p>Unlike the other two classes, 'DF.BLOB' provides a basic working implementation for 'DF.SQL' subclasses
+;; to use. You may of course subclass it if your database requires additional functionality. It requires
+;; special usage considerations, see its documentation below.</p>
+;; <h3>Example</h3>
+;; <pre>
+;; (push-autorelease-pool) ; we're going to be using DF.BLOB's.
+;; (setf db (instantiate Sqlite3 ":memory:"))
+;; (if-not db (throw-error "couldn't open db"))
+;; (db:execute-update "CREATE TABLE fish (id INTEGER PRIMARY KEY, name TEXT, weight REAL, blah BLOB)")
+;; (db:execute-update "INSERT INTO fish (name,weight) VALUES (?,?)" '("flipper" 234.123))
+;; (db:execute-update "INSERT INTO fish (name,weight) VALUES (?1,?2)" '(("?1" "catfish") ("?2" 100.3)))
+;; (db:execute-update "INSERT INTO fish (blah) VALUES (?)" (list (DF.BLOB (dup "\000" 10))))
+;; (db:execute-update "INSERT INTO fish (blah) VALUES (:cat)" (list (list ":cat" (DF.BLOB (dup "\000" 10)))))
+;; (setf sql (db:execute-query "SELECT * FROM fish"))
+;; (do-while (list? row)
+;;     (push-autorelease-pool) ; "in case" we end up fetching a lot of large blobs
+;;     (setf row (sql:next-row))
+;;     (println "row: " row)
+;;     (pop-autorelease-pool)
+;; )
+;; (deallocate sql)
+;; (deallocate db)
+;; (pop-autorelease-pool) ; deallocate the blobs we created</pre>
+;; <h3>Requirements</h3>
+;; <ul>
+;; <li>Dragonfly newLISP Web Framework (see note below)</li>
+;; <li>newLISP 10.1.9 or higher is <b>strongly recommended</b>, but any version after 10.1 should work.</li>
+;; <li>Objective newLISP 1.0</li>
+;; <li>Libraries for a supported database</li>
+;; </ul><br/>
+;; @link http://www.rundragonfly.com Dragonfly is only required for its logging functions. You can easily implement your own
+;; versions of 'DF:log-err', 'DF:log-debug', and the other functions found in Dragonfly&apos;s 'log.lsp'.
+;; <h3>Version history</h3>
+;; <b>1.1</b> &bull; 'DF.BLOB' added<br/>
+;; <b>1.0</b> &bull; initial release
+
+(constant (global 'NEWLISP64) (not (zero? (& (sys-info -1) 256))))
+; cache the function for getting a pointer
+(constant (global 'get-ptr) (if NEWLISP64 get-long get-int))
+; used to indicate that a method *must* be overwritten
+(constant (global 'throw-not-implemented) (fn()(throw-error "not defined by subclass!")))
+
+(new-class 'DF.DB)
+(new-class 'DF.SQL)
+(new-class 'DF.BLOB)
+
+; NOTE: all functions here are context-qualified because
+;       newLISP will complain if there already exists a function
+;       of that name in the MAIN context.
+
+;---------------------------------------------------------------
+; !DF.DB
+;---------------------------------------------------------------
+
+;; @syntax DF.DB
+;; <p>Represents a database connection. You create a DF.DB object
+;; like so:</p>
+;; <pre>(instantiate <DF.DB-Subclass> [<connection> [<args...>]])</pre>
+;; <p>What type should be represented by <connection> is undefined, but
+;; it&apos;s recommended that subclasses use strings. If <connection> is specified
+;; the a connected instance must be returned (or 'nil' upon failure).</p>
+;; <p>The possibly optional <args...> are specific to which subclass you're using. See its
+;; corresponding documentation.</p>
+;; <p>Instances must have code in their 'dealloc' method so that they can properly cleanup their resources
+;; (e.g. shutdown connection) if deallocated with 'deallocate'.</p>
+(context DF.DB)
+
+(define (DF.DB:DF.DB connection)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:open <connection>)
+;; <p>Returns 'true' if the connection was opened successfully, 'nil'
+;; if there was an error opening the connection, or throws an exception
+;; if already connected.</p>
+(define (DF.DB:open connection)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:close)
+;; <p>Returns 'true' if the connection was closed successfully or was
+;; already closed, or 'nil' if there was an error closing the connection.</p>
+(define (DF.DB:close)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:prepare-sql <str-sql>)
+;; @param <str-sql> A single SQL statement. Does not need to end in ';'
+;; <p>Returns a 'DF.SQL' object upon success, 'nil' on failure, or throws
+;; an exception if not connected.</p>
+;; <p><b>important:</b> If your SQL statement contains placeholders (to be
+;; bound later using 'DF.SQL:bind-params') you may not mix and match placeholder styles!
+;; Pick one placeholder style and stick with it for the entire statement.</p>
+(define (DF.DB:prepare-sql sql)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:execute-update <str-sql> [<list-params>])
+;; @param <str-sql> A single SQL statement. Does not need to end in ';'
+;; @param <list-params> A list of parameters to bind to a parameterized query
+;; <p>Same as 'DF.DB:execute-query' but returns 'true' instead of a 'DF.SQL' object upon success.
+;; Useful for SQL such as "UPDATE" and "INSERT".</p>
+(define (DF.DB:execute-update sql params)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:execute-query <str-sql> [<list-params>])
+;; @param <str-sql> A single SQL statement. Does not need to end in ';'
+;; @param <list-params> A list of parameters to bind to a parameterized query
+;; <p>A short-hand for 'DF.DB:prepare-sql' and 'DF.SQL:bind-params'. Returns
+;; a 'DF.SQL' object upon success, 'nil' on failure, or throws an exception if
+;; not connected.</p>
+;; <p><b>see:</b> documentation for 'DF.SQL:bind-params' for more info on <list-params>.
+(define (DF.DB:execute-query sql params)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:rows-for-query <str-sql> [<list-params>])
+;; <p>Same as 'DF.DB:execute-query' but retrieves all of the rows and returns them as a list of results.</p>
+;; <p><b>important:</b> If any columns contain BLOB types, you <b><i>must</i></b> have
+;; an autorelease pool allocated prior to calling this function!</p>
+(define (DF.DB:rows-for-query sql params)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:rowid)
+;; <p>Returns the row id for the last row that was inserted or throws an
+;; exception if not connected.</p>
+(define (DF.DB:rowid)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:changes)
+;; <p>Returns how many rows were affected by the last INSERT/UPDATE, or throws
+;; an exception of not connected</p>
+(define (DF.DB:changes)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:version)
+;; <p>Returns the version number of the database library being used as an integer.</p>
+(define (DF.DB:version)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:table-exists? <table-name>)
+;; <p>Returns nil or non-nil depending on whether the table named 'table-name' exists,
+;; or throws an exception if not connected.</p>
+(define (DF.DB:table-exists? table-name)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:connected?)
+;; @return nil or non-nil depending on whether this 'DF.DB' object has an active connection.
+(define (DF.DB:connected?)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.DB:last-error)
+;; @return a list of two elements: the most recent error code and a description string.
+(define (DF.DB:last-error)
+	(throw-not-implemented)
+)
+
+;---------------------------------------------------------------
+; !DF.SQL
+;---------------------------------------------------------------
+
+;; @syntax DF.SQL
+;; <p>Represents a prepared statement. It is used to bind values to a statement's parameters
+;; and retrieve the results of a query.</p>
+;; <p>You do not create a DF.SQL instance yourself but obtain one through 'DF.DB:prepare-sql'.
+;; However, if you've obtained an instance then you are responsible for freeing its memory
+;; and closing its connection when you're finished with it.</p>
+;; <p>Subclasses should make sure that their 'dealloc' method calls 'DF.SQL:close' so that
+;; statements can be freed and closed in one function call using 'deallocate'.</p>
+(context DF.SQL)
+
+;; @syntax (DF.SQL:bind-params <list-params>)
+;; <p>Binds the placeholders of this SQL statement to the values in <list-params>.</p>
+;; <p><list-params> may be simply a list of values, or an association list of key/value
+;; pairs, depending on the placeholder pattern used in the SQL. Placeholder styles
+;; <b>may not</b> be mixed per SQL statement.</p>
+;; <p>Values may be any of newLISP's primitives. To specify a BLOB wrap your string
+;; in a 'DF.BLOB':</p>
+;; <b>example:</b>
+;; <pre>
+;; ; "weight" is a REAL and "blah" is a BLOB
+;; (push-autorelease-pool) ; create our autorelease pool since we're using DF.BLOB
+;; (setf sql (db:prepare-sql "INSERT INTO fish (weight,blah) VALUES (?,?)"))
+;; (sql:bind-params (list 1043.3 (DF.BLOB (dup "\000" 5))))
+;; (println (sql:next-row))
+;; (deallocate sql)
+;; (pop-autorelease-pool)
+;; </pre>
+(define (DF.SQL:bind-params params)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.SQL:next-row)
+;; <p>Returns a row as a list from the result set of a statement, 'true' if
+;; there are no more rows to return, or 'nil' if there was an error.</p>
+;; <b>example:</b>
+;; <pre> (push-autorelease-pool) ; only necessary if there's a BLOB column
+;; (while (list? (setf row (sql:next-row)))
+;; 	(println "row: " row)
+;; )
+;; (pop-autorelease-pool) ; free any blobs</pre>
+;; <p><b>important:</b> If any columns contain BLOB types, you <b><i>must</i></b> have
+;; an autorelease pool allocated prior to calling this function!</p>
+(define (DF.SQL:next-row)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.SQL:reset)
+;; <p>Resets the statement so that it can be re-used without preparing another
+;; statement (which is more efficient). After reseting a statement you typically
+;; use 'DF.SQL:bind-params' to bind new values and then 'DF.SQL:next-row'.</p>
+(define (DF.SQL:reset)
+	(throw-not-implemented)
+)
+
+;; @syntax (DF.SQL:close)
+;; <p>Releases the resources used by the SQL statement represented by this object.
+;; You cannot use it anymore after calling this method, the only thing left to do
+;; is to 'deallocate' it, and since sublasses of 'DF.SQL' must call 'close' in
+;; their 'dealloc' methods, it&apos;s often simpler to call 'deallocate' on the object instead.</p>
+;; <p>Returns 'true' upon success, 'nil' on failure or if already closed.</p>
+(define (DF.SQL:close)
+	(throw-not-implemented)
+)
+
+;---------------------------------------------------------------
+; !DF.BLOB
+;---------------------------------------------------------------
+
+(context DF.BLOB)
+
+;; @syntax (DF.BLOB:DF.BLOB <str-blob>)
+;; <p>An object wrapper around a blob of data represented by <str-blob>, used
+;; for efficient passing of possibly large binary data.</p>
+;; <p>Unlike most other 'ObjNL' classes, you typically create an instance
+;; by simply calling its constructor instead of calling 'instantiate' yourself.
+;; It will then 'instantiate' and 'autorelease' a 'DF.BLOB' instance containing the data
+;; in 'DF.BLOB:blob'.</p>
+;; <p><b>important:</b> An autorelease pool <b>must</b> be in place when using the
+;; constructor to instantiate a blob!</p>
+;; <p><b>see:</b> the introduction to this document for example usage.</p>
+(define (DF.BLOB:DF.BLOB _blob)
+	(if (= @self @class)
+		(autorelease (instantiate @class _blob))
+		(begin (setf blob _blob) true)
+	)
+)
+
+(context MAIN)

example-site/dragonfly-framework/plugins-inactive/db/database_sqlite3.lsp

+;; @module Sqlite3
+;; @description SQLite3 subclass of DF.DB. Only lists Sqlite3 specific functions.
+;; @version 1.1
+;; @author Greg Slepak 
+;; @location http://www.taoeffect.com/newlisp/database_sqlite3.lsp.txt
+;; <h3>Features not found in newLISP's sqlite3.lsp:</h3>
+;; <ul>
+;; <li>Multiple connections</li>
+;; <li>Multiple active SQL statements</li>
+;; <li>Supports reuse of SQL statements through parameter rebinding</li>
+;; <li>Supports BLOB data-type as per 'DF.DB' and 'DF.BLOB' specification</li>
+;; <li>Conforms to generic 'DF.DB' interface</li>
+;; <li>Grabs integers directly through 64-bit function</li>
+;; <li>Can go through results row-by-row</li>
+;; <li>Allows specification of custom sqlite3 library page with 'SQLITE3_LIBRARY_PATH'</li>
+;; <li>Uses the latest Sqlite3 library functions if they are available</li>
+;; <li>Better error handling</li>
+;; </ul>
+;; <h3>Requirements</h3>
+;; See module @link http://www.taoeffect.com/newlisp/database.lsp.html DF.DB for requirements.
+;; <h3>Version history</h3>
+;; <b>1.1</b> &bull; support for 'DF.BLOB'<br/>
+;; <b>1.0</b> &bull; initial release
+
+(DF:activate-plugin "db/database")
+
+(new-class 'Sqlite3 DF.DB)
+(new-class 'Sqlite3.SQL DF.SQL)
+
+(context Sqlite3)
+
+;---------------------------------------------------------------
+; !Private imports
+;---------------------------------------------------------------
+
+(set 'lib-paths (list
+	"/usr/lib/libsqlite3.so" ; SuSE Linux
+	"/usr/local/lib/libsqlite3.so" ; Linux and BSDs
+	"/usr/pkg/lib/libsqlite3.so" ; NetBSD
+	"/usr/lib/libsqlite3.0.dylib" ; Mac OSX Darwin
+	"/usr/local/lib/libsqlite3.so" ; Solaris
+	"/usr/local/lib/libsqlite3.so.11.0" ; OpenBSD
+	(string (env "PROGRAMFILES") "/sqlite3/sqlite3.dll") ; Win32/MinGW
+	(string MAIN:SQLITE3_LIBRARY_PATH) ; allow user to define their own
+))
+
+(set 'library (lib-paths (or 
+				(find true (map file? lib-paths))
+				(throw-error "sqlite3 library not found. Set SQLITE3_LIBRARY_PATH."))))
+
+(set 'lib-funcs '(
+	"sqlite3_open"     "sqlite3_last_insert_rowid"   "sqlite3_changes"
+	"sqlite3_close"    "sqlite3_busy_timeout"        "sqlite3_libversion_number"
+	"sqlite3_prepare"  "sqlite3_errmsg"         
+))
+
+(dolist (func lib-funcs)
+	(import library func "cdecl")
+)
+
+; import possibly missing functions
+(catch (import library "sqlite3_open_v2" "cdecl") 'open_v2)
+(catch (import library "sqlite3_prepare_v2" "cdecl") 'prepare_v2)
+; if open_v2 = sqlite3_open_v2 then sqlite3_open_v2 is available
+(set 'open_v2 (= open_v2 sqlite3_open_v2)
+     'prepare_v2 (= prepare_v2 sqlite3_prepare_v2)
+)
+
+;---------------------------------------------------------------
+; !Private constants and variables
+;---------------------------------------------------------------
+
+; useful error codes
+(set 'error-codes
+  '(SQLITE_OK SQLITE_ERROR SQLITE_BUSY SQLITE_SCHEMA
+    SQLITE_ROW SQLITE_DONE)
+)
+(map constant error-codes '(0 1 5 17 100 101))
+; convenience for 'failable'
+(constant 'good-errors (list SQLITE_OK SQLITE_ROW SQLITE_DONE))
+; used for getting addresses
+(constant 'ptr-template "\000\000\000\000\000\000\000\000")
+; for use with 'last-error'
+(set 'error-code SQLITE_OK 'error-msg "No problems.")
+
+
+; cache the prepare function we'll be using
+(if prepare_v2
+	(set 'prepare_sql_func sqlite3_prepare_v2)
+	(set 'prepare_sql_func sqlite3_prepare)
+)
+
+;---------------------------------------------------------------
+; !Sqlite3 - Private API
+;---------------------------------------------------------------
+
+(define-macro (failable action)
+	(unless (find (set 'error-code (eval action)) good-errors)
+		(set 'error-msg (sqlite3_errmsg db))
+		(if (zero? error-msg)
+			(set 'error-msg nil)
+			(set 'error-msg (get-string error-msg))
+		)
+		(DF:log-err action " => " (last-error))
+		nil ; indicate failure
+	)
+)
+
+(define (assert-connected)
+	(unless db (throw-error "Database connection not open!"))
+)
+
+;---------------------------------------------------------------
+; !Public Sqlite3 API
+;---------------------------------------------------------------
+
+;; @syntax Sqlite3
+;; <p>Represents a connection to an SQLite3 database. Create one like so:</p>
+;; <pre>(instantiate Sqlite3 [<str-filepath> [<flags> [<vfs-module>]]])</pre>
+;; <p>If <str-filepath> is specified a connected instance will be returned or 'nil'
+;; upon failure to connect. If they are not specified then an unconnected instance
+;; will be returned.</p>
+;; <p><b>see:</b> documentation for 'Sqlite3:open' for an explanation of the parameters.</p>
+(define (Sqlite3:Sqlite3)
+	(unless (zero? (length $args))
+		; we can't simply call 'open' because it's a builtin primitive
+		; we also could do @self:open, but that's not necessary
+		; and could be slower. When an instance of this is created it
+		; will be rewritten to point to the new context.
+		(apply Sqlite3:open $args)
+	)
+)
+
+(define (Sqlite3:dealloc)
+	(Sqlite3:close)
+)
+
+;; @syntax (Sqlite3:open <str-filepath> [<flags> [<vfs-module>]])
+;; <p><str-filepath> specifies the path to the sqlite3 database, but it can also be
+;; ":memory:" to indicate an in-memory database.</p>
+;; <p><flags> and <vfs-module> are optional parameters as defined in the sqlite
+;; reference @link http://www.sqlite.org/c3ref/open.html documentation for
+;; 'sqlite3_open_v2'. Your installation of sqlite3 may need to be updated for this to be available.</p>
+;; <p>For return values see 'DF.DB:open'.</p>
+(define (Sqlite3:open filepath flags vfs-module , cmd (dbp ptr-template))
+	(if db (throw-error "Already connected!"))
+	(if flags
+		(if open_v2
+			(set 'cmd '(failable (sqlite3_open_v2 filepath dbp flags vfs-module)))
+			(throw-error "sqlite3_open_v2 not avaliable! Update your sqlite3 installation!")
+		)
+		(set 'cmd '(failable (sqlite3_open filepath dbp)))
+	)
+	
+	(when (eval cmd)
+		(set 'db (get-ptr dbp))
+		(Sqlite3:set-timeout 30000) ; 30 seconds
+		true ; return true regardless of whether we succeeded in setting the timeout
+	)
+)
+
+(define (Sqlite3:close)
+	(if (or (not db) (failable (sqlite3_close db)))
+		(begin (set 'db nil) true)
+		(when (= error-code SQLITE_BUSY)
+			; leaked statements are programmer error, therefore we throw an error
+			(throw-error "cannot close connection due to leaked prepared statement(s)!")
+		)
+	)
+)
+
+(define (Sqlite3:connected?)
+	(!= db nil)
+)
+
+(define (Sqlite3:prepare-sql sql , (stmtp ptr-template) (tailp ptr-template))
+	(assert-connected)
+	(when (failable (prepare_sql_func db sql -1 stmtp tailp))
+		(instantiate Sqlite3.SQL @self (get-ptr stmtp) sql)
+	)
+)
+
+(define (Sqlite3:execute-update sql params , result)
+	(assert-connected)
+	(when (setf sql (prepare-sql sql))
+		(setf result (or (not params) (sql:bind-params params)))
+		(when result (setf result (sql:next-row)))
+		(deallocate sql)
+		result
+	)
+)
+
+(define (Sqlite3:execute-query sql params)
+	(assert-connected)
+	(when (setf sql (prepare-sql sql))
+		(if (or (not params) (sql:bind-params params))
+			sql
+			(begin (deallocate sql) nil)
+		)
+	)
+)
+
+(define (Sqlite3:rows-for-query sql params , rows row)
+	(assert-connected)
+	(when (setf sql (prepare-sql sql))
+		(when (and (or (not params) (sql:bind-params params))
+		         (setf row (sql:next-row)))
+			(setf rows '())
+			(while (list? row)
+				(push row rows -1)
+				(setf row (sql:next-row))
+			)
+		)
+		(deallocate sql)
+		rows
+	)
+)
+
+(define (Sqlite3:rowid)
+	(assert-connected)
+	(sqlite3_last_insert_rowid db)
+)
+
+(define (Sqlite3:changes)
+	(assert-connected)
+	(sqlite3_changes db)
+)
+
+(define (Sqlite3:version)
+	(sqlite3_libversion_number)
+)
+
+(define (Sqlite3:table-exists? table-name)
+	(assert-connected)
+	(not (null? (rows-for-query "SELECT NULL FROM sqlite_master WHERE tbl_name = ?" (list table-name))))
+)
+
+(define (Sqlite3:last-error)
+	(list error-code error-msg)
+)
+
+;---------------------------------------------------------------
+; !Sqlite3.SQL - Sqlite3 Specific Public API
+;---------------------------------------------------------------
+
+;; @syntax (Sqlite3:set-timeout <int-ms>)
+;; <p>Sets the sqlite3's busy timeout for this connection in milliseconds.</p>
+;; <p>By default the timeout is set to 30 seconds.</p>
+;; @return nil or non-nil on success
+(define (Sqlite3:set-timeout ms)
+	(assert-connected)
+	(failable (sqlite3_busy_timeout db ms))
+)
+
+;---------------------------------------------------------------
+; !Sqlite3.SQL - Private definitions
+;---------------------------------------------------------------
+
+(context Sqlite3.SQL)
+
+; import some declaractions from Sqlite3
+(def-new 'Sqlite3:error-codes)
+(def-new 'Sqlite3:good-errors)
+(def-new 'Sqlite3:failable)
+
+(set 'lib-funcs '(                                       
+	"sqlite3_column_count"   "sqlite3_finalize"      "sqlite3_bind_parameter_index"
+	"sqlite3_column_name"    "sqlite3_reset"         "sqlite3_transfer_bindings"  
+	"sqlite3_column_type"    "sqlite3_errmsg"        "sqlite3_step"
+	"sqlite3_bind_int64"     "sqlite3_column_int64"      
+	"sqlite3_bind_double"    "sqlite3_column_double"     
+	"sqlite3_bind_null"      "sqlite3_column_text"       
+	"sqlite3_bind_text"      "sqlite3_column_blob"       
+	"sqlite3_bind_blob"      "sqlite3_column_bytes"   
+))
+
+(dolist (func lib-funcs)
+	(import Sqlite3:library func "cdecl")
+)
+
+; sqlite3 types
+(constant 'SQLITE_INTEGER 1 'SQLITE_BLOB    4
+          'SQLITE_FLOAT   2 'SQLITE_NULL    5
+          'SQLITE_TEXT    3
+)
+
+;---------------------------------------------------------------
+; !Sqlite3.SQL - Private Constructor
+;---------------------------------------------------------------
+
+(define (Sqlite3.SQL:Sqlite3.SQL _db _stmt _sql)
+	; the Sqlite3 db context (or sub-context)
+	(set 'db _db)
+	; the sqlite3_stmt pointer
+	(set 'stmt _stmt)
+	; the original SQL (in case of SQLITE_SCHEMA)
+	(set 'sql _sql)
+	; the number of columns in this table
+	(set 'num-cols (sqlite3_column_count stmt))
+	; the column types
+	(dotimes (idx num-cols)
+		; idx is a double so we use 'int' to convert it
+		(push (sqlite3_column_type stmt (int idx)) col-types -1)
+	)
+	true ; it's possible for num-cols to be 0, i.e. in an update
+)
+
+;---------------------------------------------------------------
+; !Sqlite3.SQL - Public API
+;---------------------------------------------------------------
+
+(define (Sqlite3.SQL:bind-params params)
+	(let (	first-param	(params 0)
+			strategy	binding-strategy-incremental
+		)
+		; choose strategy based on the form of the params
+		(if (and (list? first-param) (= 2 (length first-param)))
+			; if it's a doublet then we use one of these strategies:
+			(if (starts-with (first first-param) "?")
+				(set 'strategy binding-strategy-specific)
+				(set 'strategy binding-strategy-keyword)
+			)
+		)
+		; passing in no arguments resets the strategy
+		(strategy)
+		; go through the parameters and bind them
+		(dolist (param params)
+			(zero? (strategy stmt param))
+		)
+	)
+)
+
+(define (Sqlite3.SQL:next-row)
+	((eval next-row-sym))
+)
+
+(define (Sqlite3.SQL:reset)
+	(zero? (failable (sqlite3_reset stmt)))
+)
+
+(define (Sqlite3.SQL:close)
+	(when (and stmt (failable (sqlite3_finalize stmt)))
+		(setf stmt nil)
+		true ; indicate success
+	)
+)
+
+(define (Sqlite3.SQL:dealloc)
+	; we can't simply call 'close' because it's a built-in function
+	(Sqlite3.SQL:close)
+)
+
+;---------------------------------------------------------------
+; !Sqlite3.SQL - Binding
+;---------------------------------------------------------------
+
+(define (bind-param-at-index stmt value idx)
+	(cond
+		((integer? value) (failable (sqlite3_bind_int64 stmt idx value)))
+		((string? value) (failable (sqlite3_bind_text stmt idx value (length value) -1)))
+		((float? value) (failable (sqlite3_bind_double stmt idx value)))
+		((nil? value) (failable (sqlite3_bind_null stmt idx)))
+		; DF.BLOB is the vehicle for using 'sqlite3_bind_blob' instead of 'sqlite3_bind_text'
+		((context? value) (failable (sqlite3_bind_blob stmt idx value:blob (length value:blob) -1)))
+		(true (throw-error "can't bind; unhandled type for value: " value))
+	)
+)
+
+(define (binding-strategy-keyword stmt param , idx)
+	(when stmt
+		(set 'idx (sqlite3_bind_parameter_index stmt (first param)))
+		(bind-param-at-index stmt (last param) idx)
+	)
+)
+
+(define (binding-strategy-incremental stmt param)
+	(if stmt
+		(bind-param-at-index stmt param (inc .bsi-idx))
+		(set '.bsi-idx 0) ; reset it
+	)
+)
+
+(define (binding-strategy-specific stmt param)
+	(when stmt
+		(bind-param-at-index stmt (last param) (int (rest (first param))))
+	)
+)
+;---------------------------------------------------------------
+; !Sqlite3.SQL - next-row-sym stuff
+;---------------------------------------------------------------
+
+(define (get-string-cast cast ptr , temp)
+	(setf temp (get-string ptr))
+	(if-not (zero? temp) (cast temp))
+)
+
+(define (get-row , (row '()) type i ptr len buf)
+	(dotimes (idx num-cols)
+		(set 'i (int idx)) ; all loop vars are float
+		(set 'type (sqlite3_column_type stmt i))
+		(if (= type SQLITE_INTEGER)
+			(push (sqlite3_column_int64 stmt i) row -1)
+			(= type SQLITE_TEXT)
+			(push (get-string-cast string (sqlite3_column_text stmt i)) row -1)
+			(= type SQLITE_BLOB)
+			(begin
+				(set 'ptr (sqlite3_column_blob stmt i)
+				     'len (sqlite3_column_bytes stmt i)
+				     'buf (dup "\000" len))
+				(if (zero? ptr)
+					(push nil row -1)
+					(begin (cpymem ptr buf len) (push (DF.BLOB buf) row -1)))
+			)
+			; newLISP can't handle sqlite3_column_double
+			(= type SQLITE_FLOAT)
+			(push (get-string-cast float (sqlite3_column_text stmt i)) row -1)
+			(= type SQLITE_NULL)
+			(push nil row -1)
+		)
+	)
+	row
+)
+
+(define (next-row-regular)
+	(when (failable (sqlite3_step stmt))
+		(if (= error-code SQLITE_ROW)
+			(get-row)
+			(= error-code SQLITE_DONE)
+		)
+	)
+)
+
+(define (next-row-for-v1)
+	(failable (sqlite3_step stmt))
+	(if (= error-code SQLITE_ROW)
+		(begin
+			; we've obtained a lock on the table, we should no longer get SQLITE_SCHEMA
+			(setf next-row-sym 'next-row-regular)
+			(get-row)
+		)
+		(= error-code SQLITE_DONE)
+		true
+		(= error-code SQLITE_ERROR)
+		(begin
+			; this can only happen on the *first* call to step
+			; and we need to reload the statement
+			(failable (sqlite3_reset stmt))
+			(if (= SQLITE_SCHEMA error-code)
+				(and (rerun-stmt) (next-row-for-v1)) ; try again
+				(begin
+					(DF:log-err "Error " error-code " running: " sql)
+					(Sqlite3.SQL:close) ; clean up
+					nil ; this indicates failure
+				)
+			)
+		)
+	)
+)
+
+(define (rerun-stmt , tmp)
+	(when (setf tmp (db:prepare-sql sql))
+		(if (failable (sqlite3_transfer_bindings stmt tmp:stmt))
+			(begin
+				(Sqlite3.SQL:close)   ; finalize the old one
+				(setf stmt tmp:stmt)  ; grab the new pointer
+				(setf tmp:stmt nil)   ; set theirs to nil so that we can safely deallocate it
+				(deallocate tmp)      ; this should return true
+			)
+			(begin (deallocate tmp) nil)
+		)
+	)
+)
+
+; we use a symbol because next-row-for-v1 changes the value
+; of next-row-sym, and if we made it a direct reference, i.e.:
+;   (setf next-row-func next-row-regular)
+; then newLISP would crash because a function that is currently executing,
+; that being next-row-func, is being redefined while it's executing.
+(if Sqlite3:prepare_v2
+	(setf next-row-sym 'next-row-regular)
+	(setf next-row-sym 'next-row-for-v1)
+)
+
+(context MAIN)

example-site/includes/css/screen.css

 		text-decoration: none;
 	}
 
-	#api-browser blockquote, #api-browser p {
+	#api-browser blockquote, #api-browser p, #api-browser ul li, #api-browser ol li {
 		line-height:15px;
 		font-size: 11px;
 	}

example-site/views/dragonfly_builtin_plugins.html

 				</ul>
 			</li>
 		</ul>
+		<h2>Dragonfly Database</h2>
+		<p>
+			Dragonfly includes its own generic database access interface called <span class="code">DF.DB</span>.
+			It serves as an alternative to the individual database wrappers included as part of newLISP's standard modules.
+		</p>
+		<p>
+			DF.DB aims to provide a high-quality, efficient, and standard interface to various databases.
+			Currently only SQLite3 is supported but more databases are on their way. You are welcome to use
+			newLISP's various database modules as well.
+		</p>
+		<p>
+			You can find it in the <span class="code">plugins-inactive/db</span> folder. The API is
+			<a href="http://www.taoeffect.com/newlisp/index.html">online here</a>.
+		</p>
 		<h2>Artful Code Modules</h2>
 		<p>
 			Dragonfly includes several of Jeff Ober's <a href="http://static.artfulcode.net/newlisp/">Artful Code modules</a>, including functions for:

example-site/views/partials/navigation.html

 				
 				<dt>Parameters and forms</dt>
 				<dd><% (link_to "$GET, $POST, $FILES..." "dragonfly_getpost") %></dd>
-				
+			</dl>
+			<dl class="R">
 				<dt>Plugins</dt>
 				<dd><% (link_to  "Using and creating plugins" "dragonfly_plugins") %></dd>
 				<dd><% (link_to  "List of included plugins" "dragonfly_builtin_plugins") %></dd>
-			</dl>
-			<dl class="R">
+				
 				<dt>Core API</dt>
 				<dd><% (link_to  "Reference for Dragonfly's core API" "dragonfly_api") %></dd>
 			</dl>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.