(* PostgreSQL-OCAML - OCaml-interface to the PostgreSQL database Copyright (C) 2004- Markus Mottl email: markus.mottl@gmail.com WWW: http://www.ocaml.info Copyright (C) 2001 Alain Frisch (version: postgres-20010808) email: Alain.Frisch@ens.fr WWW: http://www.eleves.ens.fr/home/frisch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) (** Client-interface to the PostgreSQL database. *) (** Please learn about more details in the database documentation! *) (** {6 Types} *) (** Object ID (= Postgresql type of an object) *) type oid = int (** Handle for large objects *) type large_object (** Type of field formats *) module FFormat : sig type t = | TEXT | BINARY end (** Type of fields *) type ftype = | BOOL | BYTEA | CHAR | NAME | INT8 | INT2 | INT2VECTOR | INT4 | REGPROC | TEXT | OID | TID | XID | CID | OIDVECTOR | POINT | LSEG | PATH | BOX | POLYGON | LINE | FLOAT4 | FLOAT8 | ABSTIME | RELTIME | TINTERVAL | UNKNOWN | CIRCLE | CASH | MACADDR | INET | CIDR | ACLITEM | BPCHAR | VARCHAR | DATE | TIME | TIMESTAMP | TIMESTAMPTZ | INTERVAL | TIMETZ | BIT | VARBIT | NUMERIC | REFCURSOR | REGPROCEDURE | REGOPER | REGOPERATOR | REGCLASS | REGTYPE | RECORD | CSTRING | ANY | ANYARRAY | VOID | TRIGGER | LANGUAGE_HANDLER | INTERNAL | OPAQUE | ANYELEMENT (** Status of command/query results *) type result_status = | Empty_query (** String sent to the backend was empty *) | Command_ok (** Successful completion of a command returning no data *) | Tuples_ok (** The query successfully executed *) | Copy_out (** Copy Out (from server) data transfer started *) | Copy_in (** Copy In (to server) data transfer started *) | Bad_response (** The server's response was not understood *) | Nonfatal_error | Fatal_error (** Result of getline *) type getline_result = | EOF (** End of input reached *) | LineRead (** Entire line has been read *) | BufFull (** Buffer full but terminating newline not encountered *) (** Result of getline_async *) type getline_async_result = | EndOfData (** End-of-copy-data marker recognized *) | NoData (** No data available *) | DataRead of int (** [DataRead n] indicates [n] bytes of read data *) | PartDataRead of int (** Like [DataRead], but data only partially read *) (** Seek command ("whence") *) type seek_cmd = | SEEK_SET (** Seek from start of large object *) | SEEK_CUR (** Seek from current read/write position of large object *) | SEEK_END (** Seek from end of large object *) (** {6 Exceptions and error handling} *) (** Kinds of exceptions: [Field_out_of_range (i, n)] - access to field [i] not within range [n] [Tuple_out_of_range (i, n)] - access to tuple [i] not within range [n] [Binary] - result consists of binary tuple data [Connection_failure msg] - connection failed due to reason [msg] [Unexpected_status (stat, msg, expected)] - result status [stat] was not in [expected] due to error [msg] *) type error = | Field_out_of_range of int * int | Tuple_out_of_range of int * int | Binary | Connection_failure of string | Unexpected_status of result_status * string * (result_status list) | Cancel_failure of string (** [Error error] indicates an [error] *) exception Error of error val string_of_error : error -> string (** [string_of_error error] convert [error] to a human-readable message *) (** [Oid oid] conversion from an oid to an ftype encountered an unknown [oid] *) exception Oid of oid (** {6 Utility functions}*) external unescape_bytea : string -> string = "PQunescapeBytea_stub" (** [unescape_bytea str] unescapes binary string [str]. *) external ftype_of_oid : oid -> ftype = "ftype_of_oid_stub" (** [ftype_of_oid oid] converts [oid] to an [ftype]. *) external oid_of_ftype : ftype -> oid = "oid_of_ftype_stub" (** [oid_of_ftype ftype] converts [ftype] to an [oid]. *) val string_of_ftype : ftype -> string (** [string_of_ftype ftype] converts [ftype] to a string. *) val ftype_of_string : string -> ftype (** [string_of_ftype ftype] converts [ftype] to a string. *) (** {6 Handling results of commands and queries} *) external result_status : result_status -> string = "PQresStatus_stub" (** [result_status stat] convert status [stat] to a human-readable message *) val invalid_oid : oid (** [invalid_oid] invalid Oid. *) (** {6 Query parameters} *) val null : string (** [null] can be used as an element of the optional argument [parameters] passed to the [exec] or [send_query] method to indicate a NULL value. *) (** Class type of query results. Indices of tuples and fields start at 0! *) class type result = object (** Main routines *) method status : result_status (** [#status] @return status of a command/query result. *) method error : string (** [#error] @return error string of a result. *) (** Retrieving SELECT Result Information *) method ntuples : int (** [#ntuples] @return the number of tuples of a query result. *) method nparams : int (** [#nparams] @return the number of parameters of a prepared statement. This function is only useful when inspecting the result of [#describe_prepared]. For other types of queries it will return zero. *) method nfields : int (** [#nfields] @return the number of fields in a query result. *) method fname : int -> string (** [#fname n] @return the name of the [n]th field. @raise Error if field out of range. *) method fnumber : string -> int (** [#fnumber field] @return the index of the field named [field]. @raise Not_found if no such named field. *) method fformat : int -> FFormat.t (** [#fformat n] @return the format of the [n]th field. @raise Error if field out of range. *) method ftype : int -> ftype (** [#ftype n] @return the type of the [n]th field. @raise Oid if there was no corresponding ftype for the internal [oid]. @raise Error if field out of range. *) method paramtype : int -> ftype (** [#paramtype n] @return the datatype of the indicated statement parameter. Parameter numbers start at 0. This function is only useful when inspecting the result of [#describe_prepared]. For other types of queries it will return zero. @raise Oid if there was no corresponding ftype for the internal [oid]. @raise Error if field out of range. *) method fmod : int -> int (** [#fmod n] @return type-specific modification data of the [n]th field. @raise Error if field out of range. *) method fsize : int -> int (** [#fsize n] @return size in bytes of the [n]th field. @raise Error if field out of range. *) method binary_tuples : bool (** [#binary_tuples] @return [true] iff result contains binary tuple data. *) (** Retrieving SELECT Result Values *) method getvalue : int -> int -> string (** [#getvalue tuple field] @return value of [field] in [tuple]. @raise Error if tuple out of range. @raise Error if field out of range. *) method getisnull : int -> int -> bool (** [#getisnull tuple field] tests for a NULL-value of [field] in [tuple]. @raise Error if tuple out of range. @raise Error if field out of range. *) method getlength : int -> int -> int (** [#getlength tuple field] @return length of value in [field] of [tuple] in bytes. @raise Error if tuple out of range. @raise Error if field out of range. *) (** Retrieving Non-SELECT Result Information *) method cmd_status : string (** [#cmd_status] @return status of SQL-command associated with result. *) method cmd_tuples : string (** [#cmd_tuples] @return number of rows affected by the SQL command. *) method oid_value : oid (** [#cmd_tuples] @return the object ID of the inserted row if the SQL command was an INSERT that inserted exactly one row into a table that has OIDs. Otherwise, returns [invalid_oid]. *) (** High-level routines *) method get_fnames : string array (** [#get_fnames] @return array of field names. *) method get_fnames_lst : string list (** [#get_fnames_lst] @return list of field names. *) method get_tuple : int -> string array (** [#get_tuple n] @return all fields of the [n]th tuple. @raise Error if tuple out of range. *) method get_tuple_lst : int -> string list (** [#get_tuple_lst n] @return all fields of the [n]th tuple as list. @raise Error if tuple out of range. *) method get_all : string array array (** [#get_all] @return all tuples with all fields. *) method get_all_l : string array list (** [#get_all] @return all tuples with all fields. *) method get_all_lst : string list list (** [#get_all] @return all tuples with all fields as lists. *) end (** {6 Handling database connections} *) (** Status of a connection *) type connection_status = Ok | Bad (** Record of connection options *) type conninfo_option = { cio_keyword : string; (** Keyword of option *) cio_envvar : string; (** Fallback environment variable name *) cio_compiled : string option; (** Fallback compiled in default value *) cio_val : string option; (** Current value of option, or NULL *) cio_label : string; (** Label for field in connect dialog *) cio_dispchar : string; (** Character to display for this field in dialog *) cio_dispsize : int; (** Field size in characters for dialog *) } external conndefaults : unit -> conninfo_option array = "PQconndefaults_stub" (** [conndefaults ()] @return array of all records of type [conninfo_option] *) (** Class of connections. When [conninfo] is given, it will be used instead of all other optional arguments. *) class connection : ?host : string -> (* Default: none *) ?hostaddr : string -> (* Default: none *) ?port : string -> (* Default: none *) ?dbname : string -> (* Default: none *) ?user : string -> (* Default: none *) ?password : string -> (* Default: none *) ?options : string -> (* Default: none *) ?tty : string -> (* Default: none *) ?requiressl : string -> (* Default: none *) ?conninfo : string -> (* Default: none *) unit -> (** @raise Error if there is a connection failure. *) object (** Main routines *) method finish : unit (** [#finish] closes the connection. @raise Error if there is a connection error. *) method try_reset : unit (** [#try_reset] tries to reset the connection if it is bad. If resetting fails, the [error] exception will be raised with [Connection_failure]. @raise Error if there is a connection error. *) method reset : unit (** [#reset] resets the connection. @raise Error if there is a connection error. *) (** Asynchronous Notification *) method notifies : (string * int) option (** [#notifies] @return [Some (name, pid)] if available ([None] otherwise), where [name] is the name the of relation containing data, [pid] the process id of the backend. @raise Error if there is a connection error. *) (** Control Functions *) method set_notice_processor : (string -> unit) -> unit (** [#set_notice_processor] controls reporting of notice and warning messages generated by a connection. @raise Error if there is a connection error. *) (** Accessors *) method db : string (** [#db] @return database name of the connection. @raise Error if there is a connection error. *) method user : string (** [#user] @return user name of the connection. @raise Error if there is a connection error. *) method pass : string (** [#pass] @return password of the connection. @raise Error if there is a connection error. *) method host : string (** [#host] @return server host name of the connection. @raise Error if there is a connection error. *) method port : string (** [#port] @return port of the connection. @raise Error if there is a connection error. *) method tty : string (** [#tty] @return debug tty of the connection. @raise Error if there is a connection error. *) method options : string (** [#options] @return backend options of the connection. @raise Error if there is a connection error. *) method status : connection_status (** [#status] @return current connection status. @raise Error if there is a connection error. *) method error_message : string (** [#error_message] @return most recent error message of the connection. @raise Error if there is a connection error. *) method backend_pid : int (** [#backend] @return process id of the backend server of the connection. @raise Error if there is a connection error. *) (** Commands and Queries *) method empty_result : result_status -> result (** [empty_result stat] @return dummy result with a given status [stat]. @raise Error if there is a connection error. *) method exec : ?expect : result_status list -> ?params : string array -> ?binary_params : bool array -> string -> result (** [exec ?expect ?params ?binary_params query] synchronous execution of query or command [query]. The result status will be checked against all elements in [expect]. If [expect] is not empty and if there is no match, the exception [Unexpected_status] will be raised. Additional query parameters can be passed in the [params] array. They must not be escaped and they can be referred to in [query] as $1, $2, ... The value [null] can be used in the [params] array to denote an SQL NULL. It is possible to specify that some of the query parameters are passed as binary strings using the [binary_params] array. If no (or an empty) query parameter is passed, it is possible to emit several commands with a single call. @return result of query. @param expect default = [] @param params default = [||] @param binary_params default = [||] @raise Error if there is a connection error. @raise Error if there is an unexpected result status. *) method describe_prepared : string -> result (** [#describe_prepared stm_name] submits a request to obtain information about the specified prepared statement, and waits for completion. {!describe_prepared} allows an application to obtain information about a previously prepared statement. The [stm_name] parameter can be the empty string ("") to reference the unnamed statement, otherwise it must be the name of an existing prepared statement. On success, a {!result} with status [Command_ok] is returned. The methods {!result.nparams} and {!result.paramtype} of the class [result] can be used to obtain information about the parameters of the prepared statement, and the methods {!result.nfields}, {!result.fname} and {!result.ftype} provide information about the result columns (if any) of the statement. To prepare a statement use the SQL command PREPARE. @param stm_name The name of the previously prepared query @raise Error if there is a connection error. @see <http://www.postgresql.org/docs/8.3/interactive/sql-prepare.html> PostgreSQL documentation about [PREPARE] *) method send_query : ?params : string array -> ?binary_params : bool array -> string -> unit (** [send_query ?params ?binary_params query] asynchronous execution of query or command [query]. Additional query parameters can be passed in the [params] array. They must not be escaped and they can be referred to in [query] as $1, $2, ... The value [null] can be used in the [params] array to denote an SQL NULL. It is possible to specify that some of the query parameters are passed as binary strings using the [binary_params] array. If no (or an empty) query parameter is passed, it is possible to emit several commands with a single call. @param params default = [||] @param binary_params default = [||] @raise Error if there is a connection error. *) method send_query_prepared : ?params : string array -> ?binary_params : bool array -> string -> unit (** same as [send_query] but executes a prepared statement *) method get_result : result option (** [get_result] @return [Some result] of an asynchronous query if available or [None]. @raise Error if there is a connection error. *) (** Copy operations *) (** Low level new style *) method put_copy_data : ?pos : int -> ?len : int -> string -> bool (** [put_copy_data ?pos ?len buf]: Sends data as part of a COPY operation. See PostgreSQL docs for more information. Returns [true] if the data was sent, and [false] if the connection would block and non-blocking mode is enabled. *) method put_copy_end : unit -> bool (** [put_copy_end()]: Sends EOF as part of a COPY operation. See PostgreSQL docs for more information. Returns [true] if the data was sent, and [false] if the connection would block and non-blocking mode is enabled. *) (** Low level *) method getline : ?pos : int -> ?len : int -> string -> getline_result (** [getline ?pos ?len buf] reads a newline-terminated line of at most [len] characters into [buf] starting at position [pos]. @return getline_result @param pos default = 0 @param len default = String.length buf - pos @raise Invalid_argument if the buffer parameters are invalid. @raise Error if there is a connection error. *) method getline_async : ?pos : int -> ?len : int -> string -> getline_async_result (** [getline_async ?pos ?len buf] reads a newline-terminated line of at most [len] characters into [buf] starting at position [pos] (asynchronously). No need to call [endcopy] after receiving [EndOfData]. @return getline_async_result @param pos default = 0 @param len default = String.length buf - pos @raise Invalid_argument if the buffer parameters are invalid. @raise Error if there is a connection error. *) method putline : string -> unit (** [putline str] sends [str] to backend server. Don't use this method for binary data, use putnbytes instead! @raise Error if there is a connection error. *) method putnbytes : ?pos : int -> ?len : int -> string -> unit (** [putnbytes ?pos ?len buf] sends the substring of [buf] of length [len] starting at [pos] to backend server (use this method for binary data). @param pos default = 0 @param len default = String.length buf - pos @raise Invalid_argument if the buffer parameters are invalid. @raise Error if there is a connection error. *) method endcopy : unit (** [endcopy] synchronizes with the backend. @raise Error if there is a connection error. *) (** High level *) method copy_out : (string -> unit) -> unit (** [copy_out f] applies [f] to each line returned by backend server. @raise Error if there is a connection error. *) method copy_out_channel : out_channel -> unit (** [copy_out_channel ch] sends each line returned by backend server to output channel [ch]. @raise Error if there is a connection error. *) method copy_in_channel : in_channel -> unit (** [copy_in_channel ch] sends each line in input channel [ch] to backend server. @raise Error if there is a connection error. *) (** Asynchronous operations and non blocking mode *) method set_nonblocking : bool -> unit (** [set_nonblocking b] sets state of the connection to nonblocking if [b] is true and to blocking otherwise. @raise Error if there is a connection error. *) method is_nonblocking : bool (** [is_nonblocking] @return the blocking status of the connection. @raise Error if there is a connection error. *) method consume_input : unit (** [consume_input] consume any available input from backend. @raise Error if there is a connection error. *) method is_busy : bool (** [is_busy] @return busy status of a query. @raise Error if there is a connection error. *) method flush : bool (** [flush] attempts to flush any data queued to the backend. Returns [true] if successful, or [false] if data to flush is remaining. @raise Error if there is a connection error. *) method socket : int (** [socket] obtains the file descriptor for the backend connection socket as an integer. @raise Error if there is a connection error. *) method request_cancel : unit (** [request_cancel] requests that PostgreSQL abandon processing of the current command. @raise Error if there is a connection or cancel error. *) (** Large objects *) method lo_creat : oid (** [lo_creat] creates a new large object and returns its oid. @raise Error if there is a connection error. *) method lo_import : string -> oid (** [lo_import filename] imports an operating system file given by [filename] as a large object. @raise Error if there is a connection error. *) method lo_export : oid -> string -> unit (** [lo_export oid filename] exports the large object given by [oid] to an operating system file given by [filename]. @raise Error if there is a connection error. *) method lo_open : oid -> large_object (** [lo_open oid] opens the large object given by [oid] for reading and writing. @raise Error if there is a connection error. *) method lo_write : ?pos : int -> ?len : int -> string -> large_object -> unit (** [lo_write ?pos ?len buf lo] writes [len] bytes of buffer [buf] starting at position [pos] to large object [lo]. @param pos default = 0 @param len default = String.length buf - pos @raise Invalid_argument if the buffer parameters are invalid. @raise Error if [len] bytes could not be written. @raise Error if there is a connection error. *) method lo_read : large_object -> ?pos : int -> ?len : int -> string -> int (** [lo_read lo ?pos ?len buf] reads [len] bytes from large object [lo] to buffer [buf] starting at position [pos]. @param pos default = 0 @param len default = String.length buf - pos @raise Invalid_argument if the buffer parameters are invalid. @raise Error if [len] bytes could not be read. @raise Error if there is a connection error. *) method lo_seek : ?pos : int -> ?whence : seek_cmd -> large_object -> unit (** [lo_seek ?pos ?whence lo] seeks read/write position [pos] in large object [lo] relative to the start, current read/write position, or end of the object ([whence] is SEEK_SET, SEEK_CUR, SEEK_END respectively). @param pos default = 0 @param whence default = [SEEK_SET] @raise Error if there is a connection error. *) method lo_tell : large_object -> int (** [lo_tell lo] @return current read/write position of large object [lo]. @raise Error if there is a connection error. *) method lo_close : large_object -> unit (** [lo_close lo] closes large object [lo]. @raise Error if there is a connection error. *) method lo_unlink : oid -> unit (** [lo_unlink oid] removes the large object specified by [oid] from the database. @raise Error if there is a connection error. *) (** Escaping *) method escape_string : ?pos : int -> ?len : int -> string -> string (** [escape_string ?pos ?len str] escapes ASCII-substring [str] of length [len] starting at position [pos] for use within SQL. @param pos default = 0 @param len default = String.length str - pos *) method escape_bytea : ?pos : int -> ?len : int -> string -> string (** [escape_bytea ?pos ?len str] escapes binary substring [str] of length [len] starting at position [pos] for use within SQL. @param pos default = 0 @param len default = String.length str - pos *) end