1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
|
;; CLISP interface to PostgreSQL <http://www.postgresql.org/>
;; Copyright (C) 1999-2006 Sam Steingold
;; This is free software, distributed under the GNU GPL 2
(pushnew :PostgreSQL *features*)
(defpackage "SQL"
(:nicknames "POSTGRES" "POSTGRESQL")
(:modern t)
(:use "COMMON-LISP" "FFI")
(:shadowing-import-from "EXPORTING"
#:defconstant #:defun #:defmacro #:defvar
#:def-c-type #:def-c-enum #:def-c-struct #:def-c-var #:def-call-out))
(in-package "SQL")
(setf (documentation (find-package "SQL") 'sys::impnotes) "postgresql")
(ffi:default-foreign-language :stdc)
(eval-when (compile) (setq *foreign-guard* t))
(c-lines "#include <config.h>~%") ; local PostgreSQL config
(c-lines "#if defined(HAVE_POSTGRES_EXT_H)
# include <postgres_ext.h>
#elif defined(HAVE_POSTGRESQL_POSTGRES_EXT_H)
# include <postgresql/postgres_ext.h>
#else
# error \"PostgreSQL is not found\"
#endif~%")
(def-c-type Oid uint)
(eval-when (load compile eval)
(defconstant NAMEDATALEN 64)
(defconstant MAX-PARAM 64)
(defconstant BUFSIZ 1024))
(c-lines "#if defined(HAVE_POSTGRES_EXT_H)
# include <libpq-fe.h>
#elif defined(HAVE_POSTGRESQL_POSTGRES_EXT_H)
# include <postgresql/libpq-fe.h>
#else
# error \"PostgreSQL is not found\"
#endif~%")
(def-c-enum ConnStatusType
CONNECTION_OK
CONNECTION_BAD
CONNECTION_STARTED ; Waiting for connection to be made.
CONNECTION_MADE ; Connection OK; waiting to send.
CONNECTION_AWAITING_RESPONSE ; Waiting for a response from the postmaster.
CONNECTION_AUTH_OK ; Received authentication; waiting for backend startup.
CONNECTION_SETENV ; Negotiating environment.
CONNECTION_SSL_STARTUP ; Negotiating SSL.
CONNECTION_NEEDED) ; Internal state: connect() needed
(def-c-enum PostgresPollingStatusType
(PGRES_POLLING_FAILED 0)
PGRES_POLLING_READING ; These two indicate that one may
PGRES_POLLING_WRITING ; use select before polling again.
PGRES_POLLING_OK
PGRES_POLLING_ACTIVE) ; unused; keep for awhile for backwards compatibility
(def-c-enum ExecStatusType
(PGRES_EMPTY_QUERY 0) ; empty query string was executed
PGRES_COMMAND_OK ; a query command that doesn't return anything
; was executed properly by the backend
PGRES_TUPLES_OK ; a query command that returns tuples was executed properly
; by the backend, PGresult contains the result tuples
PGRES_COPY_OUT ; Copy Out data transfer in progress
PGRES_COPY_IN ; Copy In data transfer in progress
PGRES_BAD_RESPONSE ; an unexpected response was recv'd from the backend
PGRES_NONFATAL_ERROR ; notice or warning message
PGRES_FATAL_ERROR) ; query failed
(def-c-enum PGTransactionStatusType
PQTRANS_IDLE ; connection idle
PQTRANS_ACTIVE ; command in progress
PQTRANS_INTRANS ; idle, within transaction block
PQTRANS_INERROR ; idle, within failed transaction
PQTRANS_UNKNOW) ; cannot determine status
(def-c-enum PGVerbosity
PQERRORS_TERSE ; single-line error messages
PQERRORS_DEFAULT ; recommended style
PQERRORS_VERBOSE) ; all the facts, ma'am
;;(def-c-type PGconn (c-struct vector)) ; components unknown
;;(def-c-type PGresult (c-struct vector)) ; components unknown
;;(def-c-struct PGconn) ; components unknown
;;(def-c-struct PGresult) ; components unknown
(def-c-type PGconn c-pointer) ; components unknown
(def-c-type PGresult c-pointer) ; components unknown
(def-c-type PGcancel c-pointer) ; components unknown
(def-c-struct PGnotify
(result c-string) ; (c-array character #.NAMEDATALEN)???
(be_pid int)
(extra c-string)
;; private:
(next (c-pointer PGnotify)))
;; typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res)
;; typedef void (*PQnoticeProcessor) (void *arg, const char *message)
(def-c-type PQnoticeReceiver
(c-function (:arguments (p1 c-pointer) (res PGresult))
(:return-type nil)))
(def-c-type PQnoticeProcessor
(c-function (:arguments (p1 c-pointer) (message c-string))
(:return-type nil)))
(def-c-type pqbool char) ; for PQprint()
(def-c-struct PQprintOpt
(header pqbool) ; print output field headings and row count
(align pqbool) ; fill align the fields
(standard pqbool) ; old brain dead format
(html3 pqbool) ; output html tables
(expanded pqbool) ; expand tables
(pager pqbool) ; use pager for output if needed
(fieldSep c-string) ; field separator
(tableOpt c-string) ; insert to HTML <table ...>
(caption c-string) ; HTML <caption>
(fieldName (c-array-ptr c-string))) ; null terminated array of repalceme field names
(def-c-struct PQconninfoOption
(keyword c-string) ; The keyword of the option
(envvar c-string) ; Fallback environment variable name
(compiled c-string) ; Fallback compiled in default value
(val c-string) ; Option's current value, or NULL
(label c-string) ; Label for field in connect dialog
(dispchar c-string) ; Character to display for this field
; a connect dialog. Values are: ""
; Display entered value as is "*"
; Password field - hide value "D"
; Debug option - don't show by default
(dispsize int)) ; Field size in characters for dialog
(def-c-struct PQArgBlock
(len int)
(isint int)
(u c-pointer)) ; (c-union (ptr c-pointer) (integer int))
;; === fe-connect.c ===
;; make a new client connection to the backend
;; Asynchronous (non-blocking)
;;extern PGconn *PQconnectStart(const char *conninfo);
(def-call-out PQconnectStart (:return-type PGconn)
(:arguments (conninfo c-string)))
;;extern PostgresPollingStatusType PQconnectPoll(PGconn *conn);
(def-call-out PQconnectPoll (:return-type PostgresPollingStatusType)
(:arguments (conn PGconn)))
;; Synchronous (blocking)
(def-call-out PQconnectdb (:return-type PGconn)
(:arguments (conninfo c-string)))
(def-call-out PQsetdbLogin (:return-type PGconn)
(:arguments (pghost c-string) (pgport c-string) (pgoptions c-string)
(pgtty c-string) (dbname c-string) (login c-string)
(pwd c-string)))
(defmacro PQsetdb (a0 a1 a2 a3 a4) `(PQsetdbLogin ,a0 ,a1 ,a2 ,a3 ,a4 nil nil))
;; close the current connection and free the PGconn data structure
(def-call-out PQfinish (:arguments (conn PGconn)) (:return-type nil))
;; get info about connection options known to PQconnectdb
(def-call-out PQconndefaults (:return-type (c-ptr PQconninfoOption))
(:arguments))
;; free the data structure returned by PQconndefaults()
(def-call-out PQconninfoFree (:return-type nil)
(:arguments (connOptions (c-ptr PQconninfoOption))))
;; close the current connection and restablish a new one with the same
;; parameters:
;; Asynchronous (non-blocking)
;; extern int PQresetStart(PGconn *conn);
(def-call-out PQresetStart (:return-type int) (:arguments (conn PGconn)))
;; extern PostgresPollingStatusType PQresetPoll(PGconn *conn);
(def-call-out PQresetPoll (:return-type PostgresPollingStatusType)
(:arguments (conn PGconn)))
;; Synchronous (blocking)
;; extern void PQreset(PGconn *conn);
(def-call-out PQreset (:return-type nil) (:arguments (conn PGconn)))
;; request a cancel structure
(def-call-out PQgetCancel (:return-type PGcancel) (:arguments (conn PGconn)))
;; free a cancel structure
(def-call-out PQfreeCancel (:return-type nil) (:arguments (conn PGcancel)))
;; issue a cancel request
(def-call-out PQcancel (:return-type int)
(:arguments (cancel PGcancel)
(errbuf (c-ptr (c-array-max char #.BUFSIZ)) :out :alloca)
(errbufsize int))) ; pass BUFSIZ
;; backwards compatible version of PQcancel; not thread-safe
(def-call-out PQrequestCancel (:return-type int) (:arguments (conn PGconn)))
;; Accessor functions for PGconn objects
(def-call-out PQdb (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQuser (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQpass (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQhost (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQport (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQtty (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQoptions (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQstatus (:return-type ConnStatusType) (:arguments (conn PGconn)))
(def-call-out PQtransactionStatus (:return-type PGTransactionStatusType)
(:arguments (conn PGconn)))
(def-call-out PQparameterStatus (:return-type c-string)
(:arguments (conn PGconn) (param-name c-string)))
(def-call-out PQprotocolVersion (:return-type int) (:arguments (conn PGconn)))
(def-call-out PQserverVersion (:return-type int) (:arguments (conn PGconn)))
(def-call-out PQerrorMessage (:return-type c-string) (:arguments (conn PGconn)))
(def-call-out PQsocket (:return-type int) (:arguments (conn PGconn)))
(def-call-out PQbackendPID (:return-type int) (:arguments (conn PGconn)))
(def-call-out PQclientEncoding (:return-type int) (:arguments (conn PGconn)))
(def-call-out PQsetClientEncoding (:return-type int)
(:arguments (conn PGconn) (encoding c-string)))
;; ifdef USE_SSL
;; (def-call-out PQgetssl (:arguments (conn PGconn)) (:return-type SSL))
(def-call-out PQgetssl (:arguments (conn PGconn)) (:return-type c-pointer))
;; Tell libpq whether it needs to initialize OpenSSL (not in libpq 8.0)
(def-call-out PQinitSSL (:return-type nil) (:arguments (do_init int)))
(def-call-out PQsetErrorVerbosity (:return-type PGVerbosity)
(:arguments (conn PGconn) (verbosity PGVerbosity)))
(def-call-out PQtrace (:return-type nil)
(:arguments (conn PGconn) (debug_port c-pointer))) ; ?? FILE*
(def-call-out PQuntrace (:arguments (conn PGconn)) (:return-type nil))
(def-call-out PQsetNoticeReceiver (:return-type PQnoticeReceiver)
(:arguments (conn PGconn) (proc PQnoticeProcessor)
(arg c-pointer)))
(def-call-out PQsetNoticeProcessor (:return-type PQnoticeProcessor)
(:arguments (conn PGconn) (proc PQnoticeProcessor)
(arg c-pointer)))
;; Used to set callback that prevents concurrent access to
;; non-thread safe functions that libpq needs.
;; The default implementation uses a libpq internal mutex.
;; Only required for multithreaded apps that use kerberos
;; both within their app and for postgresql connections.
;;typedef void (*pgthreadlock_t) (int acquire);
;;extern pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler);
;; === fe-exec.c ===
;; Simple synchronous query
(def-call-out PQexec (:return-type PGresult)
(:arguments (conn PGconn) (query c-string)))
(def-call-out PQexecParams (:return-type PGresult)
(:arguments (conn PGconn) (command c-string) (nParams int)
(paramTypes (c-ptr (c-array-max Oid #.MAX-PARAM)) :out :alloca)
(paramValues (c-ptr (c-array-max c-string #.MAX-PARAM))
:out :alloca)
(paramLengths (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(paramFormats (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(resultFormat int)))
(def-call-out PQprepare (:return-type PGresult)
(:arguments (conn PGconn) (stmtName c-string) (query c-string) (nParams int)
(paramTypes (c-ptr (c-array-max Oid #.MAX-PARAM)) :out :alloca)))
(def-call-out PQexecPrepared (:return-type PGresult)
(:arguments (conn PGconn) (stmtName c-string) (nParams int)
(paramValues (c-ptr (c-array-max c-string #.MAX-PARAM))
:out :alloca)
(paramLengths (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(paramFormats (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(resultFormat int)))
;; Interface for multiple-result or asynchronous queries
(def-call-out PQsendQuery (:return-type int)
(:arguments (conn PGconn) (query c-string)))
(def-call-out PQsendQueryParams (:return-type int)
(:arguments (conn PGconn) (command c-string) (nParams int)
(paramTypes (c-ptr (c-array-max Oid #.MAX-PARAM)) :out :alloca)
(paramValues (c-ptr (c-array-max c-string #.MAX-PARAM))
:out :alloca)
(paramLengths (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(paramFormats (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(resultFormat int)))
(def-call-out PQsendPrepare (:return-type int)
(:arguments (conn PGconn) (stmtName c-string) (query c-string) (nParams int)
(paramTypes (c-ptr (c-array-max Oid #.MAX-PARAM)) :out :alloca)))
(def-call-out PQsendQueryPrepared (:return-type int)
(:arguments (conn PGconn) (stmtName c-string) (nParams int)
(paramValues (c-ptr (c-array-max c-string #.MAX-PARAM))
:out :alloca)
(paramLengths (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(paramFormats (c-ptr (c-array-max int #.MAX-PARAM)) :out :alloca)
(resultFormat int)))
(def-call-out PQgetResult (:return-type PGresult) (:arguments (conn PGconn)))
;; Routines for managing an asynchronous query
(def-call-out PQisBusy (:return-type int) (:arguments (conn PGconn)))
(def-call-out PQconsumeInput (:return-type int) (:arguments (conn PGconn)))
;; LISTEN/NOTIFY support
(def-call-out PQnotifies (:return-type (c-ptr PGnotify))
(:arguments (conn PGconn)))
;; Routines for copy in/out
(def-call-out PQputCopyData (:return-type int)
(:arguments (conn PGconn) (buffer c-string) (nbytes int)))
(def-call-out PQputCopyEnd (:return-type int)
(:arguments (conn PGconn) (errormsg c-string)))
(def-call-out PQgetCopyData (:return-type int)
(:arguments (conn PGconn) (buffer (c-ptr c-string) :out) (async int)))
;; Deprecated routines for copy in/out
(def-call-out PQgetline (:return-type int)
(:arguments (conn PGconn) (string c-string) (length int)))
(def-call-out PQputline (:return-type int)
(:arguments (conn PGconn) (string c-string)))
(def-call-out PQgetlineAsync (:return-type int)
(:arguments (conn PGconn) (buffer c-string) (bufsize int)))
(def-call-out PQputnbytes (:return-type int)
(:arguments (conn PGconn) (buffer c-string) (nbytes int)))
(def-call-out PQendcopy (:arguments (conn PGconn)) (:return-type int))
;; Set blocking/nonblocking connection to the backend
(def-call-out PQsetnonblocking (:return-type int)
(:arguments (conn PGconn) (arg int)))
(def-call-out PQisnonblocking (:return-type int) (:arguments (conn PGconn)))
;; Force the write buffer to be written (or at least try)
(def-call-out PQflush (:return-type int) (:arguments (conn PGconn)))
;; "Fast path" interface --- not really recommended for application use
(def-call-out PQfn (:return-type PGresult)
(:arguments (conn PGconn) (fnid int) (result_buf (c-ptr int) :out)
(result_len (c-ptr int) :out) (result_is_int int)
(args (c-ptr (c-array-max PQArgBlock #.MAX-PARAM)) :out :alloca)
(nargs int)))
;; Accessor functions for PGresult objects
(def-call-out PQresultStatus (:return-type ExecStatusType)
(:arguments (res PGresult)))
(def-call-out PQresStatus (:return-type c-string)
(:arguments (status ExecStatusType)))
(def-call-out PQresultErrorMessage (:return-type c-string)
(:arguments (res PGresult)))
(def-call-out PQresultErrorField (:return-type c-string)
(:arguments (res PGresult) (fieldcode int)))
(def-call-out PQntuples (:return-type int) (:arguments (res PGresult)))
(def-call-out PQnfields (:return-type int) (:arguments (res PGresult)))
(def-call-out PQbinaryTuples (:return-type int) (:arguments (res PGresult)))
(def-call-out PQfname (:return-type c-string)
(:arguments (res PGresult) (field_num int)))
(def-call-out PQfnumber (:return-type int)
(:arguments (res PGresult) (field_name c-string)))
(def-call-out PQftable (:return-type Oid)
(:arguments (res PGresult) (field_num int)))
(def-call-out PQftablecol (:return-type int)
(:arguments (res PGresult) (field_num int)))
(def-call-out PQfformat (:return-type int)
(:arguments (res PGresult) (field_num int)))
(def-call-out PQftype (:return-type Oid)
(:arguments (res PGresult) (field_num int)))
(def-call-out PQfsize (:return-type int)
(:arguments (res PGresult) (field_num int)))
(def-call-out PQfmod (:return-type int)
(:arguments (res PGresult) (field_num int)))
(def-call-out PQcmdStatus (:return-type c-string)
(:arguments (res PGresult)))
(def-call-out PQoidStatus (:return-type c-string) ; old and ugly
(:arguments (res PGresult)))
(def-call-out PQoidValue (:return-type Oid) ; new and improved
(:arguments (res PGresult)))
(def-call-out PQcmdTuples (:return-type c-string)
(:arguments (res PGresult)))
(def-call-out PQgetvalue (:return-type c-string)
(:arguments (res PGresult) (tup_num int) (field_num int)))
(def-call-out PQgetlength (:return-type int)
(:arguments (res PGresult) (tup_num int) (field_num int)))
(def-call-out PQgetisnull (:return-type int)
(:arguments (res PGresult) (tup_num int) (field_num int)))
;; Delete a PGresult
(def-call-out PQclear (:return-type nil) (:arguments (res PGresult)))
;; For freeing other alloc'd results, such as PGnotify structs
(def-call-out PQfreemem (:return-type nil) (:arguments (res c-pointer)))
(def-call-out PQmakeEmptyPGresult (:return-type PGresult)
(:arguments (conn PGconn) (status ExecStatusType)))
;; Quoting strings before inclusion in queries
(def-call-out PQescapeString (:return-type uint)
(:arguments (to (c-ptr (c-array-max char #.BUFSIZ)) :out :alloca)
(from c-string) (length uint)))
(def-call-out PQescapeBytea (:return-type c-string)
(:arguments (bintext (c-ptr (c-array-max char #.BUFSIZ)) :in-out)
(binlen uint) (bytealen (c-ptr uint) :out)))
(def-call-out PQunescapeBytea (:return-type c-string)
(:arguments (strtext (c-ptr (c-array-max char #.BUFSIZ)) :in-out)
(retbuflen (c-ptr uint) :out)))
;; === fe-print.c ===
(def-call-out PQprint (:return-type nil)
(:arguments (fout c-pointer) ; ?? FILE*
(res PGresult)
(ps (c-ptr PQprintOpt))))
(def-call-out PQdisplayTuples (:return-type nil)
(:arguments (res PGresult) (fp c-pointer) ; ?? FILE*
(fillAlign int) (fieldSep c-string)
(printHeader int) (quiet int)))
(def-call-out PQprintTuples (:return-type nil)
(:arguments (res PGresult) (fout c-pointer) ; ?? FILE*
(printAttName int) (terseOutput int) (width int)))
;; === fe-lobj.c ===
;; Large-object access routines
(def-call-out lo_open (:return-type int)
(:arguments (conn PGconn) (lobjId Oid) (mode int)))
(def-call-out lo_close (:return-type int)
(:arguments (conn PGconn) (fd int)))
(def-call-out lo_read (:return-type int)
(:arguments (conn PGconn) (fd int) (buf c-string) (len int)))
(def-call-out lo_write (:return-type int)
(:arguments (conn PGconn) (fd int) (buf c-string) (len int)))
(def-call-out lo_lseek (:return-type int)
(:arguments (conn PGconn) (fd int) (offset int) (whence int)))
(def-call-out lo_creat (:return-type Oid)
(:arguments (conn PGconn) (mode int)))
(def-call-out lo_tell (:return-type int)
(:arguments (conn PGconn) (fd int)))
(def-call-out lo_unlink (:return-type int)
(:arguments (conn PGconn) (lobjId Oid)))
(def-call-out lo_import (:return-type Oid)
(:arguments (conn PGconn) (filename c-string)))
(def-call-out lo_export (:return-type int)
(:arguments (conn PGconn) (lobjId Oid) (filename c-string)))
;; === fe-misc.c ===
;; Determine length of multibyte encoded char at *s
(def-call-out PQmblen (:return-type int)
(:arguments (s (c-pointer uchar)) (encoding int)))
;; Determine display length of multibyte encoded char at *s
(def-call-out PQdsplen (:return-type int)
(:arguments (s (c-pointer uchar)) (encoding int)))
;; Get encoding id from environment variable PGCLIENTENCODING
(def-call-out PQenv2encoding (:return-type int) (:arguments))
(provide "postgresql")
|