Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file pg_database.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182openPostgresqlopenLinks_coreopenUtility(* Pg_database
Implements the Value.database interface
for Postgresql back ends *)classotherfield(thing:Postgresql.ftype):Value.otherfield=object(_self)methodshow=matchthingwith|BOOL->"bool"|BYTEA->"bytea"|CHAR->"char"|NAME->"name"|INT8->"int8"|INT2->"int2"|INT2VECTOR->"int2vector"|INT4->"int4"|REGPROC->"regproc"|TEXT->"text"|OID->"oid"|TID->"tid"|XID->"xid"|CID->"cid"|OIDVECTOR->"oidvector"|POINT->"point"|LSEG->"lseg"|PATH->"path"|BOX->"box"|POLYGON->"polygon"|LINE->"line"|FLOAT4->"float4"|FLOAT8->"float8"|ABSTIME->"abstime"|RELTIME->"reltime"|TINTERVAL->"tinterval"|UNKNOWN->"unknown"|CIRCLE->"circle"|CASH->"cash"|MACADDR->"macaddr"|INET->"inet"|CIDR->"cidr"|ACLITEM->"aclitem"|BPCHAR->"bpchar"|VARCHAR->"varchar"|DATE->"date"|TIME->"time"|TIMESTAMP->"timestamp"|TIMESTAMPTZ->"timestamptz"|INTERVAL->"interval"|TIMETZ->"timetz"|BIT->"bit"|VARBIT->"varbit"|NUMERIC->"numeric"|REFCURSOR->"refcursor"|REGPROCEDURE->"regprocedure"|REGOPER->"regoper"|REGOPERATOR->"regoperator"|REGCLASS->"regclass"|REGTYPE->"regtype"|RECORD->"record"|CSTRING->"cstring"|ANY->"any"|ANYARRAY->"anyarray"|VOID->"void"|TRIGGER->"trigger"|LANGUAGE_HANDLER->"language_handler"|INTERNAL->"internal"|OPAQUE->"opaque"|ANYELEMENT->"anyelement"|JSON->"json"|JSONB->"jsonb"endclasspg_dbresult(pgresult:Postgresql.result)=objectinheritValue.dbvaluevaloriginal=pgresultmethodstatus:Value.db_status=matchoriginal#statuswithCommand_ok|Tuples_ok->`QueryOk|Single_tuple->`QueryError("Single tuple repsonse not handled")|Empty_query->`QueryError("String sent to the backend was empty")|Copy_out->`QueryError("Copy Out (from server) data transfer started")|Copy_in->`QueryError("Copy In (to server) data transfer started")|Copy_both->`QueryError("Copy Both data transfer started")|Bad_response->`QueryError("Bad_response : The server's response was not understood")|Nonfatal_error->`QueryError("Nonfatal_error : The server's response was not understood")|Fatal_error->`QueryError("Fatal_error : The server's response was not understood ("^original#error^")")methodnfields:int=original#nfieldsmethodntuples:int=original#ntuplesmethodfname:int->string=original#fnamemethodget_all_lst:stringlistlist=pgresult#get_all_lstmethodgetvalue:int->int->string=pgresult#getvaluemethodgettuple:int->stringarray=pgresult#get_tuplemethoderror:string=original#errorendclasspg_databasehostportdbnameuserpassword=object(self)inheritValue.databasevalconnection=trynewconnection~host:host~port:port~dbname:dbname~user:user~password:password()withPostgresql.Errormsg->failwith("PostgreSQL returned error: "^Postgresql.string_of_errormsg)methoddriver_name()="postgresql"methodexec:string->Value.dbvalue=funquery->Debug.debug_time"db#exec"(fun()->tryletraw_result=connection#execqueryinnewpg_dbresultraw_resultwithPostgresql.Errormsg->failwith("PostgreSQL returned error: "^Postgresql.string_of_errormsg))methodescape_strings=connection#escape_stringsmethodquote_fieldf="\""^Str.global_replace(Str.regexp"\"")"\"\""f^"\""(* jcheney: Added quoting to avoid problems with mysql keywords. *)method!make_insert_query(table_name,field_names,vss)=letinsert_table="insert into "^table_nameinletquoted_field_names=(List.mapself#quote_fieldfield_names)inletbody=matchfield_names,vsswith|_,[]->failwith("We should not even generate code for empty inserts.")|[],[_]->(* HACK:
PostgreSQL doesn't allow an empty tuple of columns to
be specified for an insert. *)" default values"|[],_::_::_->(* In order to handle this case we need support for the
standard mult-row insert syntax (Postgres version 8.2
and later), and we will need access to the type of the
table. In fact, we only really need the name of one of
the columns, c. Then we can do:
insert into table(c) values (c),...,(c)
*)failwith("Unable to translate a multi-row insert with empty rows to PostgreSQL")|_::_,_->letvalues=String.concat"), ("(List.map(String.concat",")vss)in"("^String.concat","quoted_field_names^") VALUES ("^values^")"ininsert_table^bodymethod!make_insert_returning_query:(string*stringlist*stringlistlist*string)->stringlist=fun(table_name,field_names,vss,returning)->[self#make_insert_query(table_name,field_names,vss)^" returning "^self#quote_fieldreturning]methodsupports_shredding()=trueendletdriver_name="postgresql"letget_pg_database_by_stringargs=matchUtility.split_stringargs':'with|(name::host::port::user::pass::_)->(* If "user" field was left empty then get the name of user running the
process. This has to be done by acquiring UID, finding corresponding
entry in passwd table and reading user's login name. *)letuser=ifuser=""thenletopenUnixin(getpwuid(getuid())).pw_nameelseuserin(newpg_databasehostportnameuserpass,Value.reconstruct_db_string(driver_name,args))|_->failwith"Insufficient arguments when establishing postgresql connection"let_=Value.register_driver(driver_name,get_pg_database_by_string)