Re: Placeholders and/or Quoting in CLSQL

Edi Weitz <[email protected]> Thu, 28 Dec 2006 00:26:35 +0100
Newsgroups gmane.lisp.clsql.general,gmane.lisp.clsql.devel
Message-ID <[email protected]>
On Fri, 22 Dec 2006 11:33:35 +0200, Shlomi Fish <shlomif-ik1l9ssToec+JF/[email protected]> wrote:

> I'm trying to translate the following Amarok script I wrote in Perl
> into Lisp:
>
> http://www.kde-apps.org/content/show.php?content=49151

What is an "Anorak script"?  From your code below it looks like you're
always calling SBCL from the shell with the --eval option.  That
doesn't look like a good idea to me - it's definitely not how you
typically work in Lisp.

> Now in the script I used SQL with placeholders:
>
> <<<<<<<<
> $statement = $dbh->prepare("SELECT * FROM people WHERE first_name = ?");
>
> $results = $statement->execute("Natan");
>>>>>>>>>
>
> However, I'm unable to find anything similar in CLSQL. Is there
> anything like that?

There's PREPARE-SQL and friends for databases like PostgreSQL which
support prepared statements.  (See doc/ref-prepared.xml which for
reasons unknown to me isn't part of the released documentation.)  This
is different from Perl's prepare, though, which is (IIRC) about
preparation on the Perl side and not necessarily on the database side.

If you're looking for a way to create SQL statements without thinking
about quoting look at the symbolic SQL syntax:

  http://clsql.b9.com/manual/ref-syntax.html
  http://www.lispworks.com/documentation/lw50/LWUG/html/lwuser-276.htm
  http://www.lispworks.com/documentation/sql-tutorial/index.html#section-4.1

> An alternative would be to quote the values into SQL strings using
> the database-safe quoting mechanism. From what I understood from the
> documentation, that's what the (clsql:sql) function does. However,
> the following code:
>
> <<<<<<<<<<<<
> (require 'clsql)
>
> (let*
>   (
>    (db 
> (clsql:connect '("/home/shlomi/.kde/share/apps/amarok/scripts-data/per-song-volume.sqlite")
>                 :database-type :sqlite3)
>        ))
>   (print db)
>   (print (clsql:query "SELECT path, volume FROM songs_volumes" :database 
> db :field-names nil))
>   (print (clsql:sql :database db "Hello 'Hi Ho ' Please ' Got"))
>   )
>>>>>>>>>>>>>

Aside: You should seriously consider to format your Lisp code like
everybody else does.  Code written in your style won't work with Lisp
IDEs like SLIME and it looks butt-ugly to experienced Lispers and will
thus reduce their willingness to help you.  Look for example here:

  http://www.lisp.org/table/style.htm   [see "Use whitespace appropriately"]
  http://norvig.com/luv-slides.ps

> generates the following error:
>
> <<<<<<<<<<<
> debugger invoked on a SIMPLE-ERROR:
>   Error during processing of --eval option (LOAD #P"db2.lisp"):
>
>   A CLSQL lisp code error occurred: No type conversion to SQL for 
> SQLITE3-DATABASE is defined for DB NULL.
>>>>>>>>>>>>

That's because of the second argument (DB) you fed into the SQL
function.  You probably thought that you're supposed to provide a
keyword argument (which makes sense, see below), but you aren't.

Try this instead:

  (clsql:sql "Hello 'Hi Ho ' Please ' Got")

> Which means I cannot quote according to a database handle. On the
> other hand the following code:
>
> <<<<<<<<<<<<
> (require 'clsql)
>
> (let*
>   (
>    (db 
> (clsql:connect '("/home/shlomi/.kde/share/apps/amarok/scripts-data/per-song-volume.sqlite")
>                 :database-type :sqlite3)
>        ))
>   (print db)
>   (print (clsql:query "SELECT path, volume FROM songs_volumes" :database 
> db :field-names nil))
>   (print (clsql:sql "Hello \\'Hi Ho \\' Please ' Got"))
>   )
>>>>>>>>>>>>>
>
> Generates the following error at (clsql:sql):
>
> <<<<<<<<<
> debugger invoked on a SIMPLE-ERROR:
>   Error during processing of --eval option (LOAD #P"db2.lisp"):
>
>   There is no applicable method for the generic function
>     #<STANDARD-GENERIC-FUNCTION CLSQL-SYS:DATABASE-TYPE (2)>
>   when called with arguments
>     (NIL).
>>>>>>>>>>
>
> So it seems I cannot use the cl:sql function with backslashes (which
> I may need).

Looks like the SQL function as it is now is bogus because it really
doesn't make much sense without specifying a database.  Below is a
patch which tries to at least use the default database (so it should
work in your case), but I think the SQL function itself should be
changed.

HTH,
Edi.



--- clsql-3.7.8/sql/expressions.lisp.orig       2006-12-27 23:51:31.000000000 +0100
+++ clsql-3.7.8/sql/expressions.lisp    2006-12-27 23:54:33.000000000 +0100
@@ -22,7 +22,7 @@
 (defvar *sql-stream* nil
   "stream which accumulates SQL output")
 
-(defun sql-output (sql-expr &optional database)
+(defun sql-output (sql-expr &optional (database *default-database*))
   "Top-level call for generating SQL strings. Returns an SQL
   string appropriate for DATABASE which corresponds to the
   supplied lisp expression SQL-EXPR."