Re: s48_extract_string?
Donald Allen <[email protected]>
| Newsgroups | gmane.lisp.scheme.scheme48 |
|---|---|
| Message-ID | <[email protected]> |
On Tue, Mar 3, 2009 at 4:14 AM, Michael Sperber <[email protected]>wrote: > > Donald Allen <[email protected]> writes: > > > After your message, and reading between the lines in the manual, I > changed it to > > > > (open 'external-calls) > > (open 'load-dynamic-externals) > > (load-dynamic-externals > > "/home/dca/Finances/Invest/Options/Scheme48/postgresql.so" #f #f #f) > > (import-lambda-definition pg_open_connection (dbname)) > > I think the complete code should be: > > (user) > (open 'external-calls) > (open 'load-dynamic-externals) > (run '(load-dynamic-externals > "/home/dca/Finances/Invest/Options/Scheme48/postgresql.so" #f #f > #f)) > (run '(import-lambda-definition pg_open_connection (dbname))) So in "Command Programs", commands, normally typed at the REPL in ",command args" syntax are now in s-exp syntax and s-expressions need to be wrapped in run in order to be evaluated properly? When there's REPL code that already distinguishes quite nicely between commands and s-expressions? Why wasn't the latter used to read from a file, so that "command programs" would have the same syntax as accepted by the REPL, instead of introducing this grossly underdocumented new command language? Frustrated, but thanks for getting me straightened out. > > > > I would like to make a general comment: in addition to the errors, > > I've already reported, the documentation is awfully cryptic. I'm an > > experienced Scheme programmer, have used MIT Scheme for many years and > > have worked together with old friends Jerry Sussman and Chris Hanson > > at MIT off and on over a period of 30 years. So if *I* can't > > understand the manual, I'd suggest that it's just not saying what it > > needs to say (this was never an issue with the MIT Scheme > > documentation). If I continue to use Scheme48 (the attraction is the > > FFI, which MIT Scheme doesn't have), I'll be happy to provide feedback > > on the documentation (and the system itself, if appropriate) to try to > > help improve it. > > That would be excellent - I've heard that often, but after all these > years with Scheme 48, I don't see the problems anymore. > > PS: It seems you're working on PostgreSQL bindings. I'm currently > working on a general DB access infrastructure with high-level queries. > Would you be interested to contribute your code? I'll be happy to give you what I have once I've finished and debugged it, but I question whether it will be useful to you. First of all, I decided to use the old FFI, because it's documented (something is better than nothing) and mature and embedded in a released version of S48. I am not going to be writing that much code that it will be difficult to move it to the new FFI when it appears in a released version. Secondly, the code I am writing is fairly specific to my application's PostgreSQL needs; it is not designed to be and it is not a general PostgreSQL interface. But having said that, you are welcome to my code when it's finished. I'm also attaching, for your reference, a file of code I found on the web, a Scheme48/PostgreSQL interface that I found on the web. I decided not to use it directly, for efficiency reasons (without the need for generality or making it public, there are efficiency hacks I can do for my application that wouldn't be acceptable in a general interface), but you may find it useful. /Don > > > -- > Cheers =8-} Mike > Friede, Völkerverständigung und überhaupt blabla >
postgresql.c
(text/x-csrc, 9.1 KB)
/* ;;; Magic 2 -- a web application framework ;;; Copyright (C) 2005-2006 Transmogrify, LLC ;;; ;;; Written by Ed Watkeys <[email protected]> ;;; Transmogrify, LLC <http://xmog.com> ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; 1. Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; 2. Redistributions in binary form must reproduce the above copyright ;;; notice, this list of conditions and the following disclaimer in the ;;; documentation and/or other materials provided with the distribution. ;;; ;;; 3. Neither the name of the company nor the names of its contributors ;;; may be used to endorse or promote products derived from this ;;; software without specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ;;; CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ;;; INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ;;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ;;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS ;;; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ;;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ;;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ;;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ;;; ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR ;;; TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF ;;; THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ;;; SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #include "libpq-fe.h" #include "scheme48.h" typedef void(*simple_proc)(PGconn*); typedef char *(*string_returning_proc)(const PGconn*); static PGconn *get_conn(s48_value conn_s48) { PGconn **conn_ptr = (PGconn **)s48_extract_byte_vector(conn_s48); return *conn_ptr; } static s48_value call_simple_proc(s48_value conn_s48, simple_proc proc) { PGconn *conn = get_conn(conn_s48); proc(conn); return S48_UNSPECIFIC; } static s48_value call_string_returning_proc(s48_value conn_s48, string_returning_proc proc) { PGconn *conn = get_conn(conn_s48); char *db = proc(conn); s48_value db_48 = s48_enter_string(db); return db_48; } s48_value pq_connect_db(s48_value conninfo_s48) { char *conninfo = s48_extract_string(conninfo_s48); PGconn *conn = PQconnectdb(conninfo); s48_value conn_s48 = s48_enter_byte_vector((char *)&conn, sizeof(conn)); return conn_s48; } s48_value pq_finish(s48_value conn_s48) { return call_simple_proc(conn_s48, PQfinish); } s48_value pq_reset(s48_value conn_s48) { return call_simple_proc(conn_s48, PQreset); } s48_value pq_db(s48_value conn_s48) { return call_string_returning_proc(conn_s48, PQdb); } s48_value pq_user(s48_value conn_s48) { return call_string_returning_proc(conn_s48, PQuser); } s48_value pq_pass(s48_value conn_s48) { return call_string_returning_proc(conn_s48, PQpass); } s48_value pq_host(s48_value conn_s48) { return call_string_returning_proc(conn_s48, PQhost); } s48_value pq_port(s48_value conn_s48) { return call_string_returning_proc(conn_s48, PQport); } s48_value pq_options(s48_value conn_s48) { return call_string_returning_proc(conn_s48, PQoptions); } s48_value pq_connection_good_p(s48_value conn_s48) { PGconn *conn = get_conn(conn_s48); ConnStatusType status = PQstatus(conn); return S48_ENTER_BOOLEAN(status == CONNECTION_OK); } s48_value pq_connection_status_impl(s48_value conn_s48) { PGconn *conn = get_conn(conn_s48); ConnStatusType status = PQstatus(conn); return status; } s48_value pq_connection_status(s48_value conn_s48) { ConnStatusType status = pq_connection_status_impl(conn_s48); return s48_enter_integer((int)status); } s48_value pq_transaction_status_impl(s48_value conn_s48) { PGconn *conn = get_conn(conn_s48); PGTransactionStatusType status = PQtransactionStatus(conn); return status; } s48_value pq_transaction_status(s48_value conn_s48) { PGTransactionStatusType status = pq_transaction_status_impl(conn_s48); return s48_enter_integer((int)status); } static void assign_param_values(s48_value param_values_s48, char **param_values, long param_count) { long i; for(i = 0; i < param_count; i++) { s48_value a = S48_CAR(param_values_s48); if (a == S48_NULL) { param_values[i] = NULL; } else { param_values[i] = strdup(s48_extract_string(a)); } param_values_s48 = S48_CDR(param_values_s48); } } static void free_param_values(char **param_values, long param_count) { int i; for(i = 0; i < param_count; i++) free(param_values[i]); } static s48_value handle_command(PGresult *result, s48_value proc_s48) { char *command_status = PQcmdStatus(result); char *command_tuples = PQcmdTuples(result); s48_value command_vector_s48; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(command_vector_s48, proc_s48); command_vector_s48 = s48_make_vector(2, S48_FALSE); S48_VECTOR_SET(command_vector_s48, 0, s48_enter_string(command_status)); S48_VECTOR_SET(command_vector_s48, 1, s48_enter_integer(atol(command_tuples))); s48_call_scheme(proc_s48, 2, S48_VECTOR_REF(command_vector_s48, 0), S48_VECTOR_REF(command_vector_s48, 1)); S48_GC_UNPROTECT(); } static s48_value handle_tuples(PGresult *result, s48_value proc_s48) { int ntuples = PQntuples(result); int nfields = PQnfields(result); s48_value field_names_s48; s48_value field_types_s48; int i, j; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(field_names_s48, field_types_s48); field_names_s48 = s48_make_vector(nfields, S48_FALSE); field_types_s48 = s48_make_vector(nfields, S48_FALSE); for(i = 0; i < nfields; i++) { S48_VECTOR_SET(field_names_s48, i, s48_enter_string(PQfname(result, i))); S48_VECTOR_SET(field_types_s48, i, s48_enter_integer(PQftype(result, i))); } { S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(proc_s48); for(i = 0; i < ntuples; i++) { s48_value row_s48 = s48_make_vector(nfields, S48_FALSE); S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(row_s48); for(j = 0; j < nfields; j++) { if(PQgetisnull(result, i, j)) S48_VECTOR_SET(row_s48, j, S48_NULL); else S48_VECTOR_SET(row_s48, j, s48_enter_string(PQgetvalue(result, i, j))); } (void)s48_call_scheme(proc_s48, 3, field_names_s48, field_types_s48, row_s48); S48_GC_UNPROTECT(); } S48_GC_UNPROTECT(); } S48_GC_UNPROTECT(); return S48_TRUE; } static s48_value list_length (s48_value list_s48) { int i = 0; while(S48_PAIR_P(list_s48)) { list_s48 = S48_CDR(list_s48); i++; } return i; } s48_value pq_exec_params(s48_value conn_s48, s48_value command_s48, s48_value proc_s48, s48_value param_values_s48) { PGconn *conn = get_conn(conn_s48); int param_count = list_length(param_values_s48); char **param_values = malloc(sizeof(char *) * param_count); s48_value ret_value = S48_FALSE; char *command = s48_extract_string(command_s48); PGresult *result; s48_value error_vector_s48; if(param_values == NULL) goto finished; assign_param_values(param_values_s48, param_values, param_count); result = PQexecParams(conn, command, param_count, NULL, (const char * const *)param_values, NULL, NULL, 0); ExecStatusType status = PQresultStatus(result); switch(status) { case PGRES_COMMAND_OK: ret_value = handle_command(result, proc_s48); break; case PGRES_TUPLES_OK: ret_value = handle_tuples(result, proc_s48); break; default: error_vector_s48 = s48_make_vector(3, S48_FALSE); S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(error_vector_s48); S48_VECTOR_SET(error_vector_s48, 0, s48_enter_integer(status)); S48_VECTOR_SET(error_vector_s48, 1, s48_enter_string(PQresStatus(status))); S48_VECTOR_SET(error_vector_s48, 2, s48_enter_string(PQresultErrorMessage(result))); S48_GC_UNPROTECT(); ret_value = error_vector_s48; break; } finished: PQclear(result); if(param_values != NULL) { free_param_values(param_values, param_count); free(param_values); } return ret_value; } void s48_on_load(void) { S48_EXPORT_FUNCTION(pq_connect_db); S48_EXPORT_FUNCTION(pq_finish); S48_EXPORT_FUNCTION(pq_reset); S48_EXPORT_FUNCTION(pq_db); S48_EXPORT_FUNCTION(pq_user); S48_EXPORT_FUNCTION(pq_pass); S48_EXPORT_FUNCTION(pq_host); S48_EXPORT_FUNCTION(pq_port); S48_EXPORT_FUNCTION(pq_options); S48_EXPORT_FUNCTION(pq_connection_good_p); S48_EXPORT_FUNCTION(pq_connection_status); S48_EXPORT_FUNCTION(pq_transaction_status); S48_EXPORT_FUNCTION(pq_exec_params); } void s48_on_reload(void) { s48_on_load(); }