a2014e2008-07-14Stephen R. van den Berg /* * This is the PostgreSQL direct network module for Pike. */ //! This is an interface to the PostgreSQL database
0412962009-01-19Stephen R. van den Berg //! server. This module is independent of any external libraries.
a2014e2008-07-14Stephen R. van den Berg //! Note that you @b{do not@} need to have a //! PostgreSQL server running on your host to use this module: you can //! connect to the database over a TCP/IP socket.
7ac2f12008-07-27Stephen R. van den Berg //!
a2014e2008-07-14Stephen R. van den Berg //! This module replaces the functionality of the older @[Sql.postgres] //! and @[Postgres.postgres] modules. //!
4e1d1f2008-08-01Stephen R. van den Berg //! This module supports the following features:
2c228b2009-02-15Stephen R. van den Berg //! @ul //! @item //! PostgreSQL network protocol version 3, authentication methods
4e1d1f2008-08-01Stephen R. van den Berg //! currently supported are: cleartext and MD5 (recommended).
2c228b2009-02-15Stephen R. van den Berg //! @item //! Streaming queries which do not buffer the whole resultset in memory. //! @item //! Automatic binary transfers to and from the database for most common
4e1d1f2008-08-01Stephen R. van den Berg //! datatypes (amongst others: integer, text and bytea types).
2c228b2009-02-15Stephen R. van den Berg //! @item
26c0ad2009-02-28Stephen R. van den Berg //! Automatic character set conversion and native wide string support. //! Supports UTF8/Unicode for multibyte characters, and all single-byte //! character sets supported by the database. //! @item
2c228b2009-02-15Stephen R. van den Berg //! SQL-injection protection by allowing just one statement per query
4e1d1f2008-08-01Stephen R. van den Berg //! and ignoring anything after the first (unquoted) semicolon in the query.
2c228b2009-02-15Stephen R. van den Berg //! @item //! COPY support for streaming up- and download. //! @item //! Accurate error messages. //! @item //! Automatic precompilation of complex queries (session cache). //! @item //! Multiple simultaneous queries on the same database connection. //! @item //! Cancelling of long running queries by force or by timeout. //! @item //! Event driven NOTIFY. //! @item //! SSL encrypted connections (optional or forced). //! @endul
0412962009-01-19Stephen R. van den Berg //! Check the PostgreSQL documentation for further details.
a2014e2008-07-14Stephen R. van den Berg //!
4e1d1f2008-08-01Stephen R. van den Berg //! @note //! Multiple simultaneous queries on the same database connection is a //! feature that none of the other database drivers for Pike support. //! So, although it's efficient, its use will make switching database drivers //! difficult. //!
a2014e2008-07-14Stephen R. van den Berg //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[Sql.Sql], @[Sql.postgres], @url{http://www.postgresql.org/docs/@}
a2014e2008-07-14Stephen R. van den Berg  #pike __REAL_VERSION__
ecbab12008-07-27Stephen R. van den Berg #include "pgsql.h"
a2014e2008-07-14Stephen R. van den Berg 
e22cab2008-07-14Stephen R. van den Berg #define ERROR(X ...) predef::error(X)
a2014e2008-07-14Stephen R. van den Berg  int _nextportal; int _closesent; int _fetchlimit=FETCHLIMIT; private int unnamedportalinuse; private int portalsinflight;
7ac2f12008-07-27Stephen R. van den Berg object _c;
a2014e2008-07-14Stephen R. van den Berg private string SSauthdata,cancelsecret; private int backendpid; private int backendstatus;
13a1202008-07-26Stephen R. van den Berg private mapping(string:mixed) options;
be07392009-02-01Stephen R. van den Berg private array(string) lastmessage=({});
39f78a2008-07-30Stephen R. van den Berg private int clearmessage;
4741cd2008-07-31Stephen R. van den Berg private int earlyclose;
a2014e2008-07-14Stephen R. van den Berg private mapping(string:array(mixed)) notifylist=([]);
26c0ad2009-02-28Stephen R. van den Berg mapping(string:string) _runtimeparameter;
ecbab12008-07-27Stephen R. van den Berg state _mstate;
a2014e2008-07-14Stephen R. van den Berg private enum querystate {queryidle,inquery,cancelpending,canceled}; private querystate qstate; private mapping(string:mapping(string:mixed)) prepareds=([]);
cb26232008-08-04Stephen R. van den Berg private mapping(string:mixed) tprepared;
a2014e2008-07-14Stephen R. van den Berg private int pstmtcount; private int pportalcount; private int totalhits;
ecbab12008-07-27Stephen R. van den Berg private int cachedepth=STATEMENTCACHEDEPTH; private int timeout=QUERYTIMEOUT; private int portalbuffersize=PORTALBUFFERSIZE;
a2014e2008-07-14Stephen R. van den Berg private int reconnected; // Number of times the connection was reset
cb26232008-08-04Stephen R. van den Berg private int sessionblocked; // Number of times the session blocked on network private int skippeddescribe; // Number of times we skipped Describe phase private int portalsopened; // Number of portals opened int _msgsreceived; // Number of protocol messages received int _bytesreceived; // Number of bytes received int _packetssent; // Number of packets sent int _bytessent; // Number of bytes sent private int warningsdropcount; // Number of uncollected warnings private int prepstmtused; // Number of times prepared statements were used private int warningscollected;
d1a5a42008-08-27Stephen R. van den Berg private int invalidatecache;
bac80c2010-02-15Stephen R. van den Berg private int connectionclosed;
a2014e2008-07-14Stephen R. van den Berg  private string host, database, user, pass; private int port;
7bca1b2012-04-04Stephen R. van den Berg private multiset cachealways=(<"BEGIN","begin","END","end","COMMIT","commit">);
9f40282008-08-27Stephen R. van den Berg private object createprefix =Regexp("^[ \t\f\r\n]*[Cc][Rr][Ee][Aa][Tt][Ee][ \t\f\r\n]");
9287132008-09-03Stephen R. van den Berg private object dontcacheprefix =Regexp("^[ \t\f\r\n]*([Ff][Ee][Tt][Cc][Hh]|[Cc][Oo][Pp][Yy])[ \t\f\r\n]");
7bca1b2012-04-04Stephen R. van den Berg private object execfetchlimit =Regexp("^[ \t\f\r\n]*(([Uu][Pp][Dd][Aa]|[Dd][Ee][Ll][Ee])[Tt][Ee]|\ [Ii][Nn][Ss][Ee][Rr][Tt])[ \t\f\r\n]|\ [ \t\f\r\n][Ll][Ii][Mm][Ii][Tt][ \t\f\r\n]+[12][; \t\f\r\n]*$");
ecbab12008-07-27Stephen R. van den Berg Thread.Mutex _querymutex; Thread.Mutex _stealmutex;
a2014e2008-07-14Stephen R. van den Berg 
be07392009-02-01Stephen R. van den Berg #define USERERROR(msg) throw(({(msg), backtrace()[..<1]}))
9287132008-09-03Stephen R. van den Berg 
c0f2b72009-04-10Stephen R. van den Berg protected string _sprintf(int type, void|mapping flags) { string res=UNDEFINED; switch(type) { case 'O':
9287132008-09-03Stephen R. van den Berg  res=sprintf(DRIVERNAME"(%s@%s:%d/%s,%d)", user,host,port,database,backendpid);
a2014e2008-07-14Stephen R. van den Berg  break; } return res; } #define BOOLOID 16 #define BYTEAOID 17 #define CHAROID 18 #define INT8OID 20 #define INT2OID 21 #define INT4OID 23 #define TEXTOID 25 #define OIDOID 26 #define XMLOID 142 #define FLOAT4OID 700
05bf882008-08-26Stephen R. van den Berg #define FLOAT8OID 701
a2014e2008-07-14Stephen R. van den Berg #define MACADDROID 829
7c4bd02008-08-09Stephen R. van den Berg #define INETOID 869 /* Force textmode */
a2014e2008-07-14Stephen R. van den Berg #define BPCHAROID 1042 #define VARCHAROID 1043 #define CTIDOID 1247 #define UUIDOID 2950
26c0ad2009-02-28Stephen R. van den Berg #define UTF8CHARSET "UTF8" #define CLIENT_ENCODING "client_encoding"
a2014e2008-07-14Stephen R. van den Berg #define PG_PROTOCOL(m,n) (((m)<<16)|(n))
1fe3992008-07-16Peter Bortas //! @decl void create()
a2014e2008-07-14Stephen R. van den Berg //! @decl void create(string host, void|string database, void|string user,@
c0f2b72009-04-10Stephen R. van den Berg //! void|string password, void|mapping(string:mixed) options)
a2014e2008-07-14Stephen R. van den Berg //!
f390972009-02-12Stephen R. van den Berg //! With no arguments, this function initialises (reinitialises if a
2c228b2009-02-15Stephen R. van den Berg //! connection has been set up previously) a connection to the
a2014e2008-07-14Stephen R. van den Berg //! PostgreSQL backend. Since PostgreSQL requires a database to be //! selected, it will try to connect to the default database. The
2c228b2009-02-15Stephen R. van den Berg //! connection may fail however, for a variety of reasons; in this case
f4c9d62009-02-15Stephen R. van den Berg //! the most likely reason is because you don't have sufficient privileges
a2014e2008-07-14Stephen R. van den Berg //! to connect to that database. So use of this particular syntax is //! discouraged. //!
2c228b2009-02-15Stephen R. van den Berg //! @param host //! Should either contain @expr{"hostname"@} or //! @expr{"hostname:portname"@}. This allows you to specify the TCP/IP //! port to connect to. If the parameter is @expr{0@} or @expr{""@}, //! it will try to connect to localhost, default port.
a2014e2008-07-14Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @param database //! Specifies the database to connect to. Not specifying this is //! only supported if the PostgreSQL backend has a default database //! configured. If you do not want to connect to any live database, //! you can use @ref{template1@}.
a2014e2008-07-14Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @param options //! Currently supports at least the following: //! @mapping
fd1c5c2012-04-02Stephen R. van den Berg //! @member int "reconnect" //! Set it to zero to disable automatic reconnects upon losing //! the connection to the database
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "use_ssl"
c0f2b72009-04-10Stephen R. van den Berg //! If the database supports and allows SSL connections, the session //! will be SSL encrypted, if not, the connection will fallback //! to plain unencrypted
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "force_ssl"
c0f2b72009-04-10Stephen R. van den Berg //! If the database supports and allows SSL connections, the session //! will be SSL encrypted, if not, the connection will abort
02dfd22012-04-06Stephen R. van den Berg //! @member int "text_query" //! Send queries to and retrieve results from the database using text //! instead of the, generally more efficient, default native binary method. //! Turning this on will allow multiple statements per query separated //! by semicolons
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "cache_autoprepared_statements"
c0f2b72009-04-10Stephen R. van den Berg //! If set to zero, it disables the automatic statement prepare and //! cache logic; caching prepared statements can be problematic //! when stored procedures and tables are redefined which leave stale //! references in the already cached prepared statements
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "client_encoding"
c0f2b72009-04-10Stephen R. van den Berg //! Character encoding for the client side, it defaults to using
1824a02009-04-10Stephen R. van den Berg //! the default encoding specified by the database, e.g. //! @ref{UTF8@} or @ref{SQL_ASCII@}.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "standard_conforming_strings"
c0f2b72009-04-10Stephen R. van den Berg //! When on, backslashes in strings must not be escaped any longer, //! @[quote()] automatically adjusts quoting strategy accordingly
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "escape_string_warning"
c0f2b72009-04-10Stephen R. van den Berg //! When on, a warning is issued if a backslash (\) appears in an //! ordinary string literal and @[standard_conforming_strings] is off, //! defaults to on
2c228b2009-02-15Stephen R. van den Berg //! @endmapping
cb26232008-08-04Stephen R. van den Berg //! For the numerous other options please check the PostgreSQL manual.
39fe7f2008-07-26Stephen R. van den Berg //!
a2014e2008-07-14Stephen R. van den Berg //! @note //! You need to have a database selected before using the sql-object, //! otherwise you'll get exceptions when you try to query it. Also //! notice that this function @b{can@} raise exceptions if the db //! server doesn't respond, if the database doesn't exist or is not //! accessible by you. //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[Postgres.postgres], @[Sql.Sql], @[select_db()], //! @url{http://search.postgresql.org/search?u=%2Fdocs%2F&q=client+connection+defaults@}
a2014e2008-07-14Stephen R. van den Berg protected void create(void|string _host, void|string _database,
c0f2b72009-04-10Stephen R. van den Berg  void|string _user, void|string _pass, void|mapping(string:mixed) _options) { pass = _pass; _pass = "CENSORED";
334f372008-08-12Stephen R. van den Berg  if(pass) String.secure(pass);
a2014e2008-07-14Stephen R. van den Berg  user = _user; database = _database; host = _host || PGSQL_DEFAULT_HOST;
39fe7f2008-07-26Stephen R. van den Berg  options = _options || ([]);
9b6a8b2009-01-12Stephen R. van den Berg  if(has_value(host,":") && sscanf(_host,"%s:%d",host,port)!=2)
a2014e2008-07-14Stephen R. van den Berg  ERROR("Error in parsing the hostname argument\n"); if(!port) port = PGSQL_DEFAULT_PORT;
ecbab12008-07-27Stephen R. van den Berg  _querymutex=Thread.Mutex(); _stealmutex=Thread.Mutex();
a2014e2008-07-14Stephen R. van den Berg  reconnect(); }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! The textual description of the last
a2014e2008-07-14Stephen R. van den Berg //! server-related error. Returns @expr{0@} if no error has occurred //! yet. It is not cleared upon reading (can be invoked multiple //! times, will return the same result until a new error occurs). //!
f28c0d2008-08-01Stephen R. van den Berg //! During the execution of a statement, this function accumulates all //! non-error messages (notices, warnings, etc.). If a statement does not //! generate any errors, this function will return all collected messages //! from the last statement. //!
2c228b2009-02-15Stephen R. van den Berg //! @note
be07392009-02-01Stephen R. van den Berg //! The string returned is not newline-terminated. //!
2c228b2009-02-15Stephen R. van den Berg //! @param clear //! To clear the error, set it to @expr{1@}.
a2014e2008-07-14Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[big_query()]
c0f2b72009-04-10Stephen R. van den Berg string error(void|int clear) { string s=lastmessage*"\n";
a2014e2008-07-14Stephen R. van den Berg  if(clear)
be07392009-02-01Stephen R. van den Berg  lastmessage=({});
cb26232008-08-04Stephen R. van den Berg  warningscollected=0;
f11ef72009-02-01Stephen R. van den Berg  return sizeof(s) && s;
a2014e2008-07-14Stephen R. van den Berg } //! This function returns a string describing what host are we talking to, //! and how (TCP/IP or UNIX sockets).
f28c0d2008-08-01Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[server_info()]
c0f2b72009-04-10Stephen R. van den Berg string host_info() { return sprintf("fd:%d TCP/IP %s:%d PID %d",
6d9aa52008-08-21Stephen R. van den Berg  _c?_c.query_fd():-1,host,port,backendpid);
a2014e2008-07-14Stephen R. van den Berg }
c0f2b72009-04-10Stephen R. van den Berg final private object getsocket(void|int nossl) { object lcon = Stdio.File();
13a1202008-07-26Stephen R. van den Berg  if(!lcon.connect(host,port)) return UNDEFINED;
7ac2f12008-07-27Stephen R. van den Berg 
39fe7f2008-07-26Stephen R. van den Berg  object fcon;
13a1202008-07-26Stephen R. van den Berg #if constant(SSL.sslfile)
c0f2b72009-04-10Stephen R. van den Berg  if(!nossl && (options->use_ssl || options->force_ssl)) { PD("SSLRequest\n"); { object c=.pgsql_util.PGassist(); lcon.write(({c.plugint32(8),c.plugint32(PG_PROTOCOL(1234,5679))})); } switch(lcon.read(1)) { case "S": SSL.context context = SSL.context(); context->random = Crypto.Random.random_string; fcon=.pgsql_util.PGconnS(lcon, context); if(fcon) return fcon; default:lcon.close(); if(!lcon.connect(host,port)) return UNDEFINED; case "N": if(options->force_ssl) ERROR("Encryption not supported on connection to %s:%d\n", host,port); }
39fe7f2008-07-26Stephen R. van den Berg  } #else if(options->force_ssl) ERROR("Encryption library missing, cannot establish connection to %s:%d\n", host,port);
488ce72008-07-24Stephen R. van den Berg #endif
ecbab12008-07-27Stephen R. van den Berg  fcon=.pgsql_util.PGconn(lcon,this);
39fe7f2008-07-26Stephen R. van den Berg  return fcon;
a2014e2008-07-14Stephen R. van den Berg } //! Cancels the currently running query. //!
2c228b2009-02-15Stephen R. van den Berg //! @seealso //! @[reload()], @[resync()] //! //! @note
a2014e2008-07-14Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg void cancelquery() { if(qstate==inquery) { qstate=cancelpending;
a2014e2008-07-14Stephen R. van den Berg  object lcon; PD("CancelRequest\n");
7ac2f12008-07-27Stephen R. van den Berg  if(!(lcon=getsocket(1)))
a2014e2008-07-14Stephen R. van den Berg  ERROR("Cancel connect failed\n");
7ac2f12008-07-27Stephen R. van den Berg  lcon.write(({_c.plugint32(16),_c.plugint32(PG_PROTOCOL(1234,5678)), _c.plugint32(backendpid),cancelsecret}));
a2014e2008-07-14Stephen R. van den Berg  lcon.close(); } }
26c0ad2009-02-28Stephen R. van den Berg //! Changes the connection charset. When set to @ref{UTF8@}, the query, //! parameters and results can be Pike-native wide strings.
d6f86e2008-08-20Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @param charset //! A PostgreSQL charset name.
d6f86e2008-08-20Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[get_charset()], @[create()], //! @url{http://search.postgresql.org/search?u=%2Fdocs%2F&q=character+sets@}
d6f86e2008-08-20Stephen R. van den Berg void set_charset(string charset)
845f4f2009-04-10Stephen R. van den Berg { big_query(sprintf("SET CLIENT_ENCODING TO '%s'",quote(charset)));
d6f86e2008-08-20Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! The PostgreSQL name for the current connection charset.
d6f86e2008-08-20Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[set_charset()], @[getruntimeparameters()], //! @url{http://search.postgresql.org/search?u=%2Fdocs%2F&q=character+sets@}
d6f86e2008-08-20Stephen R. van den Berg string get_charset()
26c0ad2009-02-28Stephen R. van den Berg { return _runtimeparameter[CLIENT_ENCODING];
d6f86e2008-08-20Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! Currently active runtimeparameters for //! the open session; these are initialised by the @ref{options@} parameter
cb26232008-08-04Stephen R. van den Berg //! during session creation, and then processed and returned by the server. //! Common values are:
2c228b2009-02-15Stephen R. van den Berg //! @mapping
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "client_encoding"
1824a02009-04-10Stephen R. van den Berg //! Character encoding for the client side, e.g. //! @ref{UTF8@} or @ref{SQL_ASCII@}.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "server_encoding"
c0f2b72009-04-10Stephen R. van den Berg //! Character encoding for the server side as determined when the
1824a02009-04-10Stephen R. van den Berg //! database was created, e.g. @ref{UTF8@} or @ref{SQL_ASCII@}
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "DateStyle"
1824a02009-04-10Stephen R. van den Berg //! Date parsing/display, e.g. @ref{ISO, DMY@}
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "TimeZone"
1824a02009-04-10Stephen R. van den Berg //! Default timezone used by the database, e.g. @ref{localtime@}
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "standard_conforming_strings"
c0f2b72009-04-10Stephen R. van den Berg //! When on, backslashes in strings must not be escaped any longer
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "session_authorization"
c0f2b72009-04-10Stephen R. van den Berg //! Displays the authorisationrole which the current session runs under
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "is_superuser"
c0f2b72009-04-10Stephen R. van den Berg //! Indicates if the current authorisationrole has database-superuser //! privileges
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "integer_datetimes"
c0f2b72009-04-10Stephen R. van den Berg //! Reports wether the database supports 64-bit-integer dates and times
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "server_version"
1824a02009-04-10Stephen R. van den Berg //! Shows the server version, e.g. @ref{8.3.3@}
2c228b2009-02-15Stephen R. van den Berg //! @endmapping
cb26232008-08-04Stephen R. van den Berg //! //! The values can be changed during a session using SET commands to the //! database. //! For other runtimeparameters check the PostgreSQL documentation.
cbe2762008-08-01Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @seealso //! @url{http://search.postgresql.org/search?u=%2Fdocs%2F&q=client+connection+defaults@} //! //! @note
cbe2762008-08-01Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
26c0ad2009-02-28Stephen R. van den Berg mapping(string:string) getruntimeparameters() { return _runtimeparameter+([]);
cbe2762008-08-01Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! A set of statistics for the current session: //! @mapping
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "warnings_dropped"
cb26232008-08-04Stephen R. van den Berg //! Number of warnings/notices generated by the database but not
f4c9d62009-02-15Stephen R. van den Berg //! collected by the application by using @[error()] after the statements
cb26232008-08-04Stephen R. van den Berg //! that generated them.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "skipped_describe_count"
cb26232008-08-04Stephen R. van den Berg //! Number of times the driver skipped asking the database to //! describe the statement parameters because it was already cached.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "used_prepared_statements"
cb26232008-08-04Stephen R. van den Berg //! Numer of times prepared statements were used from cache instead of //! reparsing in the current session.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "current_prepared_statements"
cb26232008-08-04Stephen R. van den Berg //! Cache size of currently prepared statements.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "current_prepared_statement_hits"
cb26232008-08-04Stephen R. van den Berg //! Sum of the number hits on statements in the current statement cache.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "prepared_portal_count"
cb26232008-08-04Stephen R. van den Berg //! Total number of prepared portals generated.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "prepared_statement_count"
cb26232008-08-04Stephen R. van den Berg //! Total number of prepared statements generated.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "portals_opened_count"
cb26232008-08-04Stephen R. van den Berg //! Total number of portals opened, i.e. number of statements issued //! to the database.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "blocked_count"
cb26232008-08-04Stephen R. van den Berg //! Number of times the driver had to (briefly) wait for the database to //! send additional data.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "bytes_received"
cb26232008-08-04Stephen R. van den Berg //! Total number of bytes received from the database so far.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "messages_received"
cb26232008-08-04Stephen R. van den Berg //! Total number of messages received from the database (one SQL-statement //! requires multiple messages to be exchanged).
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "bytes_sent"
cb26232008-08-04Stephen R. van den Berg //! Total number of bytes sent to the database so far.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "packets_sent"
cb26232008-08-04Stephen R. van den Berg //! Total number of packets sent to the database (one packet usually //! contains multiple messages).
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "reconnect_count"
cb26232008-08-04Stephen R. van den Berg //! Number of times the connection to the database has been lost.
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "portals_in_flight"
cb26232008-08-04Stephen R. van den Berg //! Currently still open portals, i.e. running statements.
2c228b2009-02-15Stephen R. van den Berg //! @endmapping
cb26232008-08-04Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @note
cb26232008-08-04Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg mapping(string:mixed) getstatistics() { mapping(string:mixed) stats=([
cb26232008-08-04Stephen R. van den Berg  "warnings_dropped":warningsdropcount, "skipped_describe_count":skippeddescribe, "used_prepared_statements":prepstmtused, "current_prepared_statements":sizeof(prepareds), "current_prepared_statement_hits":totalhits, "prepared_portal_count":pportalcount, "prepared_statement_count":pstmtcount, "portals_opened_count":portalsopened, "blocked_count":sessionblocked, "messages_received":_msgsreceived, "bytes_received":_bytesreceived, "packets_sent":_packetssent, "bytes_sent":_bytessent, "reconnect_count":reconnected, "portals_in_flight":portalsinflight, ]); return stats; }
2c228b2009-02-15Stephen R. van den Berg //! @param newdepth //! Sets the new cachedepth for automatic caching of prepared statements.
a2014e2008-07-14Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @returns //! The previous cachedepth. //! //! @note
a2014e2008-07-14Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg int setcachedepth(void|int newdepth) { int olddepth=cachedepth;
488ce72008-07-24Stephen R. van den Berg  if(!zero_type(newdepth) && newdepth>=0)
a2014e2008-07-14Stephen R. van den Berg  cachedepth=newdepth; return olddepth; }
2c228b2009-02-15Stephen R. van den Berg //! @param newtimeout //! Sets the new timeout for long running queries.
a2014e2008-07-14Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @returns //! The previous timeout. //! //! @note
a2014e2008-07-14Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg int settimeout(void|int newtimeout) { int oldtimeout=timeout;
488ce72008-07-24Stephen R. van den Berg  if(!zero_type(newtimeout) && newtimeout>0)
a2014e2008-07-14Stephen R. van den Berg  timeout=newtimeout; return oldtimeout; }
f4c9d62009-02-15Stephen R. van den Berg //! @param newportalbuffersize //! Sets the new portalbuffersize for buffering partially concurrent queries. //! //! @returns //! The previous portalbuffersize.
a2014e2008-07-14Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @note
a2014e2008-07-14Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg int setportalbuffersize(void|int newportalbuffersize) { int oldportalbuffersize=portalbuffersize;
488ce72008-07-24Stephen R. van den Berg  if(!zero_type(newportalbuffersize) && newportalbuffersize>0)
a2014e2008-07-14Stephen R. van den Berg  portalbuffersize=newportalbuffersize; return oldportalbuffersize; }
f4c9d62009-02-15Stephen R. van den Berg //! @param newfetchlimit //! Sets the new fetchlimit to interleave queries. //! //! @returns //! The previous fetchlimit.
a2014e2008-07-14Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @note
a2014e2008-07-14Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg int setfetchlimit(void|int newfetchlimit) { int oldfetchlimit=_fetchlimit;
488ce72008-07-24Stephen R. van den Berg  if(!zero_type(newfetchlimit) && newfetchlimit>=0)
a2014e2008-07-14Stephen R. van den Berg  _fetchlimit=newfetchlimit; return oldfetchlimit; }
c0f2b72009-04-10Stephen R. van den Berg final private string glob2reg(string glob) { if(!glob||!sizeof(glob))
a2014e2008-07-14Stephen R. van den Berg  return "%"; return replace(glob,({"*","?","\\","%","_"}),({"%","_","\\\\","\\%","\\_"})); }
c0f2b72009-04-10Stephen R. van den Berg final private string a2nls(array(string) msg) { return msg*"\n"+"\n";
a2014e2008-07-14Stephen R. van den Berg }
c0f2b72009-04-10Stephen R. van den Berg final private string pinpointerror(void|string query,void|string offset) { if(!query)
a2014e2008-07-14Stephen R. van den Berg  return ""; int k=(int)offset; if(k<=0) return MARKSTART+query+MARKEND; return MARKSTART+(k>1?query[..k-2]:"")+MARKERROR+query[k-1..]+MARKEND; }
bac80c2010-02-15Stephen R. van den Berg private void phasedreconnect() { connectionclosed=1; if(!reconnect(1)) { sleep(RECONNECTDELAY); if(!reconnect(1)) { sleep(RECONNECTBACKOFF); reconnect(1); } } }
c0f2b72009-04-10Stephen R. van den Berg final int _decodemsg(void|state waitforstate) {
a2014e2008-07-14Stephen R. van den Berg #ifdef DEBUG { array line; #ifdef DEBUGMORE line=backtrace(); #endif PD("Waiting for state %O %O\n",waitforstate,line&&line[sizeof(line)-2]); } #endif
c0f2b72009-04-10Stephen R. van den Berg  while(_mstate!=waitforstate) { if(_mstate!=unauthenticated) { if(qstate==cancelpending) qstate=canceled,sendclose(); if(_c.flushed && qstate==inquery && !_c.bpeek(0)) { int tcurr=time(); int told=tcurr+timeout; sessionblocked++; while(!_c.bpeek(told-tcurr)) if((tcurr=time())-told>=timeout) { sendclose();cancelquery(); break; }
a2014e2008-07-14Stephen R. van den Berg  } }
7ac2f12008-07-27Stephen R. van den Berg  int msgtype=_c.getbyte(); int msglen=_c.getint32();
cb26232008-08-04Stephen R. van den Berg  _msgsreceived++; _bytesreceived+=1+msglen;
a2014e2008-07-14Stephen R. van den Berg  enum errortype { noerror=0, protocolerror, protocolunsupported }; errortype errtype=noerror;
c0f2b72009-04-10Stephen R. van den Berg  switch(msgtype) { void storetiming() { tprepared->trun=gethrtime()-tprepared->trunstart; m_delete(tprepared,"trunstart"); tprepared = UNDEFINED;
cb26232008-08-04Stephen R. van den Berg  };
c0f2b72009-04-10Stephen R. van den Berg  void getcols() { int bintext=_c.getbyte(); array a; int cols=_c.getint16(); msglen-=4+1+2+2*cols; foreach(a=allocate(cols,([]));;mapping m) m->type=_c.getint16(); if(_c.portal) // Discard column info, and make it line oriented { a=({(["type":bintext?BYTEAOID:TEXTOID,"name":"line"])});
7ac2f12008-07-27Stephen R. van den Berg  _c.portal->_datarowdesc=a;
c0f2b72009-04-10Stephen R. van den Berg  } _mstate=gotrowdescription;
a2014e2008-07-14Stephen R. van den Berg  };
c0f2b72009-04-10Stephen R. van den Berg  array(string) getstrings() { string s; if(msglen<1) errtype=protocolerror; s=_c.getstring(msglen); if(s[--msglen]) errtype=protocolerror; if(!msglen) return ({}); s=s[..msglen-1];msglen=0; return s/"\0";
a2014e2008-07-14Stephen R. van den Berg  };
c0f2b72009-04-10Stephen R. van den Berg  mapping(string:string) getresponse() { mapping(string:string) msgresponse=([]); msglen-=4; foreach(getstrings();;string f)
a2014e2008-07-14Stephen R. van den Berg  if(sizeof(f))
c0f2b72009-04-10Stephen R. van den Berg  msgresponse[f[..0]]=f[1..]; PD("%O\n",msgresponse); return msgresponse;
a2014e2008-07-14Stephen R. van den Berg  };
c8942c2009-04-10Stephen R. van den Berg  array(string) showbindings() { array(string) msgs=({}); array from;
fa693a2009-09-21Stephen R. van den Berg  if(_c.portal && (from = _c.portal->_params))
c8942c2009-04-10Stephen R. van den Berg  { array to,paramValues; [from,to,paramValues] = from; if(sizeof(paramValues)) { string val; int i; string fmt=sprintf("%%%ds %%3s %%.61s",max(@map(from,sizeof))); foreach(paramValues;i;val) msgs+=({sprintf(fmt,from[i],to[i],sprintf("%O",val))}); } } return msgs; };
a2014e2008-07-14Stephen R. van den Berg  case 'R':PD("Authentication\n"); { string sendpass;
c0f2b72009-04-10Stephen R. van den Berg  int authtype; msglen-=4+4; switch(authtype=_c.getint32()) { case 0:PD("Ok\n");
ecbab12008-07-27Stephen R. van den Berg  _mstate=authenticated;
c0f2b72009-04-10Stephen R. van den Berg  break; case 2:PD("KerberosV5\n"); errtype=protocolunsupported; break; case 3:PD("ClearTextPassword\n"); sendpass=pass; break; case 4:PD("CryptPassword\n");
2830e72009-04-18Stephen R. van den Berg  errtype=protocolunsupported;
c0f2b72009-04-10Stephen R. van den Berg  break; case 5:PD("MD5Password\n"); if(msglen<4) errtype=protocolerror;
a2014e2008-07-14Stephen R. van den Berg #if constant(Crypto.MD5.hash) #define md5hex(x) String.string2hex(Crypto.MD5.hash(x))
c0f2b72009-04-10Stephen R. van den Berg  sendpass=md5hex(pass+user); sendpass="md5"+md5hex(sendpass+_c.getstring(msglen));
a2014e2008-07-14Stephen R. van den Berg #else
c0f2b72009-04-10Stephen R. van den Berg  _c.getstring(msglen); errtype=protocolunsupported;
a2014e2008-07-14Stephen R. van den Berg #endif
c0f2b72009-04-10Stephen R. van den Berg  msglen=0; break; case 6:PD("SCMCredential\n"); errtype=protocolunsupported; break; case 7:PD("GSS\n"); errtype=protocolunsupported; break; case 9:PD("SSPI\n"); errtype=protocolunsupported; break; case 8:PD("GSSContinue\n"); errtype=protocolunsupported; if(msglen<1) errtype=protocolerror; SSauthdata=_c.getstring(msglen);msglen=0; break; default:PD("Unknown Authentication Method %c\n",authtype); errtype=protocolunsupported; break; } switch(errtype) { case noerror: if(_mstate==unauthenticated) _c.sendcmd(({"p",_c.plugint32(4+sizeof(sendpass)+1), sendpass,"\0"}),1); break; default: case protocolunsupported: ERROR("Unsupported authenticationmethod %c\n",authtype); break; } break;
a2014e2008-07-14Stephen R. van den Berg  } case 'K':PD("BackendKeyData\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4+4;backendpid=_c.getint32();cancelsecret=_c.getstring(msglen); msglen=0; break;
a2014e2008-07-14Stephen R. van den Berg  case 'S':PD("ParameterStatus\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4;
a2014e2008-07-14Stephen R. van den Berg  { array(string) ts=getstrings();
c0f2b72009-04-10Stephen R. van den Berg  if(sizeof(ts)==2) { _runtimeparameter[ts[0]]=ts[1]; PD("%s=%s\n",ts[0],ts[1]); } else errtype=protocolerror;
a2014e2008-07-14Stephen R. van den Berg  }
c0f2b72009-04-10Stephen R. van den Berg  break;
a2014e2008-07-14Stephen R. van den Berg  case 'Z':PD("ReadyForQuery\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4+1; backendstatus=_c.getbyte(); _mstate=readyforquery; qstate=queryidle; _closesent=0; break;
a2014e2008-07-14Stephen R. van den Berg  case '1':PD("ParseComplete\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; _mstate=parsecomplete; break;
a2014e2008-07-14Stephen R. van den Berg  case 't':
c0f2b72009-04-10Stephen R. van den Berg  PD("ParameterDescription (for %s)\n",
7ac2f12008-07-27Stephen R. van den Berg  _c.portal?_c.portal->_portalname:"DISCARDED");
a2014e2008-07-14Stephen R. van den Berg  { array a;
c0f2b72009-04-10Stephen R. van den Berg  int cols=_c.getint16(); msglen-=4+2+4*cols; foreach(a=allocate(cols);int i;)
7ac2f12008-07-27Stephen R. van den Berg  a[i]=_c.getint32();
a2014e2008-07-14Stephen R. van den Berg #ifdef DEBUGMORE
c0f2b72009-04-10Stephen R. van den Berg  PD("%O\n",a);
a2014e2008-07-14Stephen R. van den Berg #endif
c0f2b72009-04-10Stephen R. van den Berg  if(_c.portal)
7ac2f12008-07-27Stephen R. van den Berg  _c.portal->_datatypeoid=a;
c0f2b72009-04-10Stephen R. van den Berg  _mstate=gotparameterdescription; break;
a2014e2008-07-14Stephen R. van den Berg  } case 'T':
c0f2b72009-04-10Stephen R. van den Berg  PD("RowDescription (for %s)\n",
7ac2f12008-07-27Stephen R. van den Berg  _c.portal?_c.portal->_portalname:"DISCARDED");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4+2;
a2014e2008-07-14Stephen R. van den Berg  { array a;
c0f2b72009-04-10Stephen R. van den Berg  foreach(a=allocate(_c.getint16());int i;) { string s;
7ac2f12008-07-27Stephen R. van den Berg  msglen-=sizeof(s=_c.getstring())+1;
c0f2b72009-04-10Stephen R. van den Berg  mapping(string:mixed) res=(["name":s]); msglen-=4+2+4+2+4+2; res->tableoid=_c.getint32()||UNDEFINED;
7ac2f12008-07-27Stephen R. van den Berg  res->tablecolattr=_c.getint16()||UNDEFINED;
c0f2b72009-04-10Stephen R. van den Berg  res->type=_c.getint32();
7ac2f12008-07-27Stephen R. van den Berg  { int len=_c.getint16();
c0f2b72009-04-10Stephen R. van den Berg  res->length=len>=0?len:"variable";
a2014e2008-07-14Stephen R. van den Berg  }
02dfd22012-04-06Stephen R. van den Berg  res->atttypmod=_c.getint32(); res->formatcode=_c.getint16(); // Currently broken in Postgres
c0f2b72009-04-10Stephen R. van den Berg  a[i]=res; }
a2014e2008-07-14Stephen R. van den Berg #ifdef DEBUGMORE
c0f2b72009-04-10Stephen R. van den Berg  PD("%O\n",a);
a2014e2008-07-14Stephen R. van den Berg #endif
7ac2f12008-07-27Stephen R. van den Berg  if(_c.portal) _c.portal->_datarowdesc=a;
c0f2b72009-04-10Stephen R. van den Berg  _mstate=gotrowdescription; break;
a2014e2008-07-14Stephen R. van den Berg  } case 'n':PD("NoData\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; _c.portal->_datarowdesc=({});
7b4d232008-09-03Stephen R. van den Berg  _c.portal->_fetchlimit=0; // disables subsequent Executes
c0f2b72009-04-10Stephen R. van den Berg  _mstate=gotrowdescription; break;
a2014e2008-07-14Stephen R. van den Berg  case '2':PD("BindComplete\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; _mstate=bindcomplete; break;
a2014e2008-07-14Stephen R. van den Berg  case 'D':PD("DataRow\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; if(_c.portal) { if(tprepared) storetiming();
49a3282008-07-25Stephen R. van den Berg #ifdef USEPGsql
c0f2b72009-04-10Stephen R. van den Berg  _c.decodedatarow(msglen);msglen=0;
49a3282008-07-25Stephen R. van den Berg #else
c0f2b72009-04-10Stephen R. van den Berg  array a, datarowdesc;
7ac2f12008-07-27Stephen R. van den Berg  _c.portal->_bytesreceived+=msglen; datarowdesc=_c.portal->_datarowdesc;
c0f2b72009-04-10Stephen R. van den Berg  int cols=_c.getint16();
b156722008-08-25Stephen R. van den Berg  int atext = _c.portal->_alltext; // cache locally for speed
02dfd22012-04-06Stephen R. van den Berg  int forcetext = _c.portal->_forcetext; // cache locally for speed
26c0ad2009-02-28Stephen R. van den Berg  string cenc=_runtimeparameter[CLIENT_ENCODING];
488ce72008-07-24Stephen R. van den Berg  a=allocate(cols,UNDEFINED);
c0f2b72009-04-10Stephen R. van den Berg  msglen-=2+4*cols;
02dfd22012-04-06Stephen R. van den Berg  foreach(datarowdesc;int i;mapping m)
c0f2b72009-04-10Stephen R. van den Berg  { int collen=_c.getint32(); if(collen>0) { msglen-=collen; mixed value;
02dfd22012-04-06Stephen R. van den Berg  switch(int typ=m->type) { case FLOAT4OID: #if SIZEOF_FLOAT>=8 case FLOAT8OID: #endif if(!atext) { value=(float)_c.getstring(collen); break; } default:value=_c.getstring(collen);
c0f2b72009-04-10Stephen R. van den Berg  break;
02dfd22012-04-06Stephen R. van den Berg  case CHAROID: value=atext?_c.getstring(1):_c.getbyte();
c0f2b72009-04-10Stephen R. van den Berg  break; case BOOLOID:value=_c.getbyte();
02dfd22012-04-06Stephen R. van den Berg  switch(value) { case 'f':value=0; break; case 't':value=1; }
b156722008-08-25Stephen R. van den Berg  if(atext)
aaa4562008-08-21Stephen R. van den Berg  value=value?"t":"f";
c0f2b72009-04-10Stephen R. van den Berg  break;
02dfd22012-04-06Stephen R. van den Berg  case TEXTOID: case BPCHAROID: case VARCHAROID:
b156722008-08-25Stephen R. van den Berg  value=_c.getstring(collen);
02dfd22012-04-06Stephen R. van den Berg  if(cenc==UTF8CHARSET && catch(value=utf8_to_string(value))) ERROR("%O contains non-%s characters\n",value,UTF8CHARSET);
c0f2b72009-04-10Stephen R. van den Berg  break;
02dfd22012-04-06Stephen R. van den Berg  case INT8OID:case INT2OID: case OIDOID:case INT4OID: if(forcetext) { value=_c.getstring(collen); if(!atext) value=(int)value; } else { switch(typ) { case INT8OID:value=_c.getint64(); break; case INT2OID:value=_c.getint16(); break; case OIDOID: case INT4OID:value=_c.getint32(); } if(atext) value=(string)value; }
c0f2b72009-04-10Stephen R. van den Berg  }
a2014e2008-07-14Stephen R. van den Berg  a[i]=value;
c0f2b72009-04-10Stephen R. van den Berg  } else if(!collen) a[i]=""; }
49a3282008-07-25Stephen R. van den Berg  a=({a});
7ac2f12008-07-27Stephen R. van den Berg  _c.portal->_datarows+=a; _c.portal->_inflight-=sizeof(a); #endif
c0f2b72009-04-10Stephen R. van den Berg  } else
7ac2f12008-07-27Stephen R. van den Berg  _c.getstring(msglen),msglen=0;
c0f2b72009-04-10Stephen R. van den Berg  _mstate=dataready; break;
a2014e2008-07-14Stephen R. van den Berg  case 's':PD("PortalSuspended\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; _mstate=portalsuspended; break;
a2014e2008-07-14Stephen R. van den Berg  case 'C':PD("CommandComplete\n"); { msglen-=4;
c0f2b72009-04-10Stephen R. van den Berg  if(msglen<1) errtype=protocolerror; string s=_c.getstring(msglen-1); if(_c.portal) { if(tprepared) storetiming(); _c.portal->_statuscmdcomplete=s; } PD("%s\n",s); if(_c.getbyte()) errtype=protocolerror; msglen=0; _mstate=commandcomplete; break;
a2014e2008-07-14Stephen R. van den Berg  } case 'I':PD("EmptyQueryResponse\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; _mstate=commandcomplete; break;
a2014e2008-07-14Stephen R. van den Berg  case '3':PD("CloseComplete\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; _closesent=0; break;
a2014e2008-07-14Stephen R. van den Berg  case 'd':PD("CopyData\n");
c0f2b72009-04-10Stephen R. van den Berg  if(tprepared) storetiming(); msglen-=4; if(msglen<0) errtype=protocolerror; if(_c.portal) { _c.portal->_bytesreceived+=msglen; _c.portal->_datarows+=({({_c.getstring(msglen)})}); }
a2014e2008-07-14Stephen R. van den Berg  msglen=0;
c0f2b72009-04-10Stephen R. van den Berg  _mstate=dataready; break;
a2014e2008-07-14Stephen R. van den Berg  case 'H':PD("CopyOutResponse\n");
c0f2b72009-04-10Stephen R. van den Berg  getcols(); break;
a2014e2008-07-14Stephen R. van den Berg  case 'G':PD("CopyInResponse\n");
c0f2b72009-04-10Stephen R. van den Berg  getcols(); _mstate=copyinresponse; break;
a2014e2008-07-14Stephen R. van den Berg  case 'c':PD("CopyDone\n");
c0f2b72009-04-10Stephen R. van den Berg  msglen-=4; break;
a2014e2008-07-14Stephen R. van den Berg  case 'E':PD("ErrorResponse\n");
b133b02008-08-06Stephen R. van den Berg  { mapping(string:string) msgresponse;
c0f2b72009-04-10Stephen R. van den Berg  msgresponse=getresponse();
bac80c2010-02-15Stephen R. van den Berg  void preplastmessage() { lastmessage=({sprintf("%s %s:%s %s\n (%s:%s:%s)", msgresponse->S,msgresponse->C,msgresponse->P||"",msgresponse->M, msgresponse->F||"",msgresponse->R||"",msgresponse->L||"")}); };
cb26232008-08-04Stephen R. van den Berg  warningsdropcount+=warningscollected; warningscollected=0;
c0f2b72009-04-10Stephen R. van den Berg  switch(msgresponse->C) { case "P0001": lastmessage=({sprintf("%s: %s",msgresponse->S,msgresponse->M)});
be07392009-02-01Stephen R. van den Berg  USERERROR(a2nls(lastmessage
c8942c2009-04-10Stephen R. van den Berg  +({pinpointerror(_c.portal->_query,msgresponse->P)}) +showbindings()));
bac80c2010-02-15Stephen R. van den Berg  case "57P01":case "57P02":case "57P03": preplastmessage();phasedreconnect(); PD(a2nls(lastmessage)); USERERROR(a2nls(lastmessage));
c0f2b72009-04-10Stephen R. van den Berg  case "08P01":case "42P05":
d1a5a42008-08-27Stephen R. van den Berg  errtype=protocolerror; case "XX000":case "42883":case "42P01": invalidatecache=1;
a2014e2008-07-14Stephen R. van den Berg  default:
bac80c2010-02-15Stephen R. van den Berg  preplastmessage();
be07392009-02-01Stephen R. van den Berg  if(msgresponse->D) lastmessage+=({msgresponse->D}); if(msgresponse->H) lastmessage+=({msgresponse->H}); lastmessage+=({
c8942c2009-04-10Stephen R. van den Berg  pinpointerror(_c.portal&&_c.portal->_query,msgresponse->P)+
be07392009-02-01Stephen R. van den Berg  pinpointerror(msgresponse->q,msgresponse->p)}); if(msgresponse->W) lastmessage+=({msgresponse->W});
c8942c2009-04-10Stephen R. van den Berg  lastmessage+=showbindings();
c0f2b72009-04-10Stephen R. van den Berg  switch(msgresponse->S) { case "PANIC":werror(a2nls(lastmessage)); }
be07392009-02-01Stephen R. van den Berg  USERERROR(a2nls(lastmessage));
c0f2b72009-04-10Stephen R. van den Berg  } break;
b133b02008-08-06Stephen R. van den Berg  }
a2014e2008-07-14Stephen R. van den Berg  case 'N':PD("NoticeResponse\n");
b133b02008-08-06Stephen R. van den Berg  { mapping(string:string) msgresponse;
c0f2b72009-04-10Stephen R. van den Berg  msgresponse=getresponse(); if(clearmessage) { warningsdropcount+=warningscollected;
cb26232008-08-04Stephen R. van den Berg  clearmessage=warningscollected=0;
c0f2b72009-04-10Stephen R. van den Berg  lastmessage=({}); } warningscollected++; lastmessage=({sprintf("%s %s: %s",
be07392009-02-01Stephen R. van den Berg  msgresponse->S,msgresponse->C,msgresponse->M)});
c0f2b72009-04-10Stephen R. van den Berg  break;
b133b02008-08-06Stephen R. van den Berg  }
a2014e2008-07-14Stephen R. van den Berg  case 'A':PD("NotificationResponse\n"); { msglen-=4+4;
c0f2b72009-04-10Stephen R. van den Berg  int pid=_c.getint32(); string condition,extrainfo=UNDEFINED; { array(string) ts=getstrings(); switch(sizeof(ts)) { case 0:errtype=protocolerror;
a2014e2008-07-14Stephen R. van den Berg  break;
c0f2b72009-04-10Stephen R. van den Berg  default:errtype=protocolerror; case 2:extrainfo=ts[1]; case 1:condition=ts[0]; } } PD("%d %s\n%s\n",pid,condition,extrainfo); runcallback(pid,condition,extrainfo); break;
a2014e2008-07-14Stephen R. van den Berg  }
c015742008-08-21Stephen R. van den Berg  default:
c0f2b72009-04-10Stephen R. van den Berg  if(msgtype!=-1) { PD("Unknown message received %c\n",msgtype); msglen-=4;PD("%O\n",_c.getstring(msglen));msglen=0; errtype=protocolunsupported;
c015742008-08-21Stephen R. van den Berg  }
c0f2b72009-04-10Stephen R. van den Berg  else { array(string) msg=lastmessage;
2d42a62010-03-23Stephen R. van den Berg  if(_mstate!=unauthenticated) phasedreconnect(),msg+=lastmessage;
be07392009-02-01Stephen R. van den Berg  string s=sizeof(msg)?a2nls(msg):"";
c0f2b72009-04-10Stephen R. van den Berg  ERROR("%sConnection lost to database %s@%s:%d/%s %d\n", s,user,host,port,database,backendpid);
c015742008-08-21Stephen R. van den Berg  }
c0f2b72009-04-10Stephen R. van den Berg  break;
a2014e2008-07-14Stephen R. van den Berg  } if(msglen) errtype=protocolerror;
c0f2b72009-04-10Stephen R. van den Berg  switch(errtype) { case protocolunsupported: ERROR("Unsupported servermessage received %c\n",msgtype); break;
a2014e2008-07-14Stephen R. van den Berg  case protocolerror:
be07392009-02-01Stephen R. van den Berg  array(string) msg=lastmessage;
bac80c2010-02-15Stephen R. van den Berg  lastmessage=({});phasedreconnect();msg+=lastmessage;
be07392009-02-01Stephen R. van den Berg  string s=sizeof(msg)?a2nls(msg):"";
c0f2b72009-04-10Stephen R. van den Berg  ERROR("%sProtocol error with database %s\n",s,host_info()); break;
a2014e2008-07-14Stephen R. van den Berg  case noerror:
c0f2b72009-04-10Stephen R. van den Berg  break;
a2014e2008-07-14Stephen R. van den Berg  } if(zero_type(waitforstate)) break; }
ecbab12008-07-27Stephen R. van den Berg  PD("Found state %O\n",_mstate); return _mstate;
a2014e2008-07-14Stephen R. van den Berg }
0e0cfa2008-07-25Henrik Grubbström (Grubba) #ifndef UNBUFFEREDIO
c0f2b72009-04-10Stephen R. van den Berg private int read_cb(mixed foo, string d) { _c.unread(d);
49a3282008-07-25Stephen R. van den Berg  do _decodemsg();
7ac2f12008-07-27Stephen R. van den Berg  while(_c.bpeek(0)==1);
a2014e2008-07-14Stephen R. van den Berg  return 0; }
0e0cfa2008-07-25Henrik Grubbström (Grubba) #endif
a2014e2008-07-14Stephen R. van den Berg 
cb26232008-08-04Stephen R. van den Berg //! Closes the connection to the database, any running queries are //! terminated instantly. //!
2c228b2009-02-15Stephen R. van den Berg //! @note
cb26232008-08-04Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg void close() { cancelquery();
7ac2f12008-07-27Stephen R. van den Berg  if(_c) _c.sendterminate();
b259512011-10-03Henrik Grubbström (Grubba)  _c=0;
a2014e2008-07-14Stephen R. van den Berg }
c0f2b72009-04-10Stephen R. van den Berg void destroy() { close();
cb26232008-08-04Stephen R. van den Berg }
bf26b92010-03-23Stephen R. van den Berg private int reconnect(void|int force)
c0f2b72009-04-10Stephen R. van den Berg { Thread.MutexKey connectmtxkey; if(_c) { reconnected++;
cb26232008-08-04Stephen R. van den Berg  prepstmtused=0;
a2014e2008-07-14Stephen R. van den Berg  if(!force)
7ac2f12008-07-27Stephen R. van den Berg  _c.sendterminate();
b259512011-10-03Henrik Grubbström (Grubba)  else _c.close(); _c=0;
cb26232008-08-04Stephen R. van den Berg  foreach(prepareds;;mapping tp) m_delete(tp,"preparedname");
02dfd22012-04-06Stephen R. van den Berg  if(!options->reconnect || !(connectmtxkey = _stealmutex.trylock(2)))
6d9aa52008-08-21Stephen R. van den Berg  return 0; // Recursive reconnect, bailing out }
c0f2b72009-04-10Stephen R. van den Berg  if(!(_c=getsocket())) { string msg=sprintf("Couldn't connect to database on %s:%d",host,port); if(force) { lastmessage+=({msg});
6d9aa52008-08-21Stephen R. van den Berg  return 0; } else
be07392009-02-01Stephen R. van den Berg  ERROR(msg+"\n");
a2014e2008-07-14Stephen R. van den Berg  } _closesent=0;
ecbab12008-07-27Stephen R. van den Berg  _mstate=unauthenticated;
a2014e2008-07-14Stephen R. van den Berg  qstate=queryidle;
26c0ad2009-02-28Stephen R. van den Berg  _runtimeparameter=([]);
7ac2f12008-07-27Stephen R. van den Berg  array(string) plugbuf=({"",_c.plugint32(PG_PROTOCOL(3,0))});
a2014e2008-07-14Stephen R. van den Berg  if(user) plugbuf+=({"user\0",user,"\0"}); if(database) plugbuf+=({"database\0",database,"\0"});
02dfd22012-04-06Stephen R. van den Berg  options->reconnect=zero_type(options->reconnect) || options->reconnect;
fd1c5c2012-04-02Stephen R. van den Berg  foreach(options
02dfd22012-04-06Stephen R. van den Berg  -(<"use_ssl","force_ssl","cache_autoprepared_statements","reconnect", "text_query">);
aaa4562008-08-21Stephen R. van den Berg  string name;mixed value)
cb26232008-08-04Stephen R. van den Berg  plugbuf+=({name,"\0",(string)value,"\0"});
a2014e2008-07-14Stephen R. van den Berg  plugbuf+=({"\0"}); int len=4; foreach(plugbuf;;string s) len+=sizeof(s);
7ac2f12008-07-27Stephen R. van den Berg  plugbuf[0]=_c.plugint32(len);
4741cd2008-07-31Stephen R. van den Berg  _c.write(plugbuf);
a2014e2008-07-14Stephen R. van den Berg  PD("%O\n",plugbuf);
bf26b92010-03-23Stephen R. van den Berg  { mixed err=catch(_decodemsg(readyforquery)); if(err) if(force) return 0; else throw(err); }
26c0ad2009-02-28Stephen R. van den Berg  PD("%O\n",_runtimeparameter);
c0f2b72009-04-10Stephen R. van den Berg  if(force) { lastmessage+=({sprintf("Reconnected to database %s",host_info())});
b133b02008-08-06Stephen R. van den Berg  runcallback(backendpid,"_reconnect","");
6d9aa52008-08-21Stephen R. van den Berg  }
bf26b92010-03-23Stephen R. van den Berg  return 1;
a2014e2008-07-14Stephen R. van den Berg } //! @decl void reload() //!
e7621f2009-02-02Stephen R. van den Berg //! For PostgreSQL this function performs the same function as @[resync()].
f28c0d2008-08-01Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[resync()], @[cancelquery()]
c0f2b72009-04-10Stephen R. van den Berg void reload() { resync();
e7621f2009-02-02Stephen R. van den Berg } //! @decl void resync() //! //! Resyncs the database session; typically used to make sure the session is //! not still in a dangling transaction. //! //! If called while queries/portals are still in-flight, this function //! is a no-op. //! //! If called while the connection is in idle state, the function is //! lightweight and briefly touches base with the database server to //! make sure client and server are in sync. //! //! If issued while inside a transaction, it will rollback the transaction, //! close all open cursors, drop all temporary tables and reset all //! session variables to their default values. //!
2c228b2009-02-15Stephen R. van den Berg //! @seealso //! @[cancelquery()], @[reload()] //! //! @note
e7621f2009-02-02Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg void resync(void|int special) { mixed err;
a2014e2008-07-14Stephen R. van den Berg  int didsync;
c0f2b72009-04-10Stephen R. van den Berg  if(err = catch { sendclose(1);
a2014e2008-07-14Stephen R. van den Berg  PD("Portalsinflight: %d\n",portalsinflight);
c0f2b72009-04-10Stephen R. van den Berg  if(!portalsinflight) { if(!earlyclose) { PD("Sync\n"); _c.sendcmd(({"S",_c.plugint32(4)}),2); } didsync=1; if(!special) { _decodemsg(readyforquery); switch(backendstatus) { case 'T':case 'E': foreach(prepareds;;mapping tp) { m_delete(tp,"datatypeoid"); m_delete(tp,"datarowdesc"); }
e7621f2009-02-02Stephen R. van den Berg  big_query("ROLLBACK"); big_query("RESET ALL"); big_query("CLOSE ALL"); big_query("DISCARD TEMP"); }
c0f2b72009-04-10Stephen R. van den Berg  }
a2014e2008-07-14Stephen R. van den Berg  }
4741cd2008-07-31Stephen R. van den Berg  earlyclose=0;
c0f2b72009-04-10Stephen R. van den Berg  }) { earlyclose=0;
a2014e2008-07-14Stephen R. van den Berg  PD("%O\n",err);
6d9aa52008-08-21Stephen R. van den Berg  if(!reconnect(1))
be07392009-02-01Stephen R. van den Berg  ERROR(a2nls(lastmessage));
a2014e2008-07-14Stephen R. van den Berg  } else if(didsync && special==2)
49a3282008-07-25Stephen R. van den Berg  _decodemsg(readyforquery);
a2014e2008-07-14Stephen R. van den Berg #ifndef UNBUFFEREDIO
7ac2f12008-07-27Stephen R. van den Berg  _c.set_read_callback(read_cb);
a2014e2008-07-14Stephen R. van den Berg #endif } //! This function allows you to connect to a database. Due to //! restrictions of the Postgres frontend-backend protocol, you always //! have to be connected to a database, so in fact this function just //! allows you to connect to a different database on the same server. //! //! @note //! This function @b{can@} raise exceptions if something goes wrong
f4c9d62009-02-15Stephen R. van den Berg //! (backend process not running, insufficient privileges...)
a2014e2008-07-14Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[create()]
c0f2b72009-04-10Stephen R. van den Berg void select_db(string dbname) { database=dbname;
a2014e2008-07-14Stephen R. van den Berg  reconnect();
b133b02008-08-06Stephen R. van den Berg  reconnected=0;
a2014e2008-07-14Stephen R. van den Berg } //! With PostgreSQL you can LISTEN to NOTIFY events. //! This function allows you to detect and handle such events. //! //! @param condition //! Name of the notification event we're listening //! to. A special case is the empty string, which matches all events, //! and can be used as fallback function which is called only when the
b133b02008-08-06Stephen R. van den Berg //! specific condition is not handled. Another special case is
f4c9d62009-02-15Stephen R. van den Berg //! @ref{_reconnect@} which gets called whenever the connection unexpectedly
b133b02008-08-06Stephen R. van den Berg //! drops and reconnects to the database.
a2014e2008-07-14Stephen R. van den Berg //! //! @param notify_cb //! Function to be called on receiving a notification-event of
f4c9d62009-02-15Stephen R. van den Berg //! condition @ref{condition@}.
a2014e2008-07-14Stephen R. van den Berg //! The callback function is invoked with
c0f2b72009-04-10Stephen R. van den Berg //! @expr{void notify_cb(pid,condition,extrainfo, .. args);@}
f4c9d62009-02-15Stephen R. van den Berg //! @ref{pid@} is the process id of the database session that originated //! the event. @ref{condition@} contains the current condition. //! @ref{extrainfo@} contains optional extra information specified by
a2014e2008-07-14Stephen R. van den Berg //! the database.
f4c9d62009-02-15Stephen R. van den Berg //! The rest of the arguments to @ref{notify_cb@} are passed //! verbatim from @ref{args@}.
a2014e2008-07-14Stephen R. van den Berg //! The callback function must return no value.
7ac2f12008-07-27Stephen R. van den Berg //!
a2014e2008-07-14Stephen R. van den Berg //! @param selfnotify //! Normally notify events generated by your own session are ignored.
f4c9d62009-02-15Stephen R. van den Berg //! If you want to receive those as well, set @ref{selfnotify@} to one.
7ac2f12008-07-27Stephen R. van den Berg //!
a2014e2008-07-14Stephen R. van den Berg //! @param args
f4c9d62009-02-15Stephen R. van den Berg //! Extra arguments to pass to @ref{notify_cb@}.
7ac2f12008-07-27Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @note
a2014e2008-07-14Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface. void set_notify_callback(string condition, void|function(int,string,string,mixed ...:void) notify_cb,void|int selfnotify,
c0f2b72009-04-10Stephen R. van den Berg  mixed ... args) { if(!notify_cb)
a2014e2008-07-14Stephen R. van den Berg  m_delete(notifylist,condition);
c0f2b72009-04-10Stephen R. van den Berg  else { array old=notifylist[condition];
a2014e2008-07-14Stephen R. van den Berg  if(!old) old=({notify_cb}); if(selfnotify||args) old+=({selfnotify}); if(args) old+=args; notifylist[condition]=old; } }
c0f2b72009-04-10Stephen R. van den Berg final private void runcallback(int pid,string condition,string extrainfo) { array cb;
b133b02008-08-06Stephen R. van den Berg  if((cb=notifylist[condition]||notifylist[""]) && (pid!=backendpid || sizeof(cb)>1 && cb[1])) cb[0](pid,condition,extrainfo,@cb[2..]); }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! The given string, but escapes/quotes all contained magic characters //! according to the quoting rules of the current session for non-binary //! arguments in textual SQL-queries. //! //! @note //! Quoting must not be done for parameters passed in bindings.
a2014e2008-07-14Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[big_query()], @[quotebinary()], @[create()]
26c0ad2009-02-28Stephen R. van den Berg string quote(string s) { string r=_runtimeparameter->standard_conforming_strings;
a2014e2008-07-14Stephen R. van den Berg  if(r && r=="on") return replace(s, "'", "''"); return replace(s, ({ "'", "\\" }), ({ "''", "\\\\" }) ); }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! The given string, but escapes/quotes all contained magic characters
f4c9d62009-02-15Stephen R. van den Berg //! for binary (bytea) arguments in textual SQL-queries.
2c228b2009-02-15Stephen R. van den Berg //! //! @note //! Quoting must not be done for parameters passed in bindings.
cb26232008-08-04Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[big_query()], @[quote()]
cb26232008-08-04Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @note
cb26232008-08-04Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg string quotebinary(string s) { return replace(s, ({ "'", "\\", "\0" }), ({ "''", "\\\\", "\\000" }) );
cb26232008-08-04Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! This function creates a new database (assuming we
f4c9d62009-02-15Stephen R. van den Berg //! have sufficient privileges to do this).
2c228b2009-02-15Stephen R. van den Berg //! //! @param db //! Name of the new database.
a2014e2008-07-14Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[drop_db()]
c0f2b72009-04-10Stephen R. van den Berg void create_db(string db) { big_query("CREATE DATABASE :db",([":db":db]));
a2014e2008-07-14Stephen R. van den Berg } //! This function destroys a database and all the data it contains (assuming
f4c9d62009-02-15Stephen R. van den Berg //! we have sufficient privileges to do so). It is not possible to delete
cb26232008-08-04Stephen R. van den Berg //! the database you're currently connected to. You can connect to database
2c228b2009-02-15Stephen R. van den Berg //! @ref{template1@} to avoid connecting to any live database. //! //! @param db //! Name of the database to be deleted.
a2014e2008-07-14Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[create_db()]
c0f2b72009-04-10Stephen R. van den Berg void drop_db(string db) { big_query("DROP DATABASE :db",([":db":db]));
a2014e2008-07-14Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! A string describing the server we are
a2014e2008-07-14Stephen R. van den Berg //! talking to. It has the form @expr{"servername/serverversion"@} //! (like the HTTP protocol description) and is most useful in //! conjunction with the generic SQL-server module.
f28c0d2008-08-01Stephen R. van den Berg //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[host_info()]
26c0ad2009-02-28Stephen R. van den Berg string server_info () { return DRIVERNAME"/"+(_runtimeparameter->server_version||"unknown");
a2014e2008-07-14Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! An array of the databases available on the server. //! //! @param glob //! If specified, list only those databases matching it.
c0f2b72009-04-10Stephen R. van den Berg array(string) list_dbs (void|string glob) { array row,ret=({}); object res=big_query("SELECT d.datname " "FROM pg_database d " "WHERE d.datname ILIKE :glob " "ORDER BY d.datname", ([":glob":glob2reg(glob)])); while(row=res->fetch_row()) ret+=({row[0]}); return ret;
a2014e2008-07-14Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! An array containing the names of all the tables and views in the
a2014e2008-07-14Stephen R. van den Berg //! path in the currently selected database.
2c228b2009-02-15Stephen R. van den Berg //! //! @param glob //! If specified, list only the tables with matching names.
c0f2b72009-04-10Stephen R. van den Berg array(string) list_tables (void|string glob) { array row,ret=({}); // This query might not work on PostgreSQL 7.4 object res=big_query( // due to missing schemasupport "SELECT CASE WHEN 'public'=n.nspname THEN '' ELSE n.nspname||'.' END " " ||c.relname AS name " "FROM pg_catalog.pg_class c " " LEFT JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace " "WHERE c.relkind IN ('r','v') AND n.nspname<>'pg_catalog' " " AND n.nspname !~ '^pg_toast' AND pg_catalog.pg_table_is_visible(c.oid) " " AND c.relname ILIKE :glob " " ORDER BY 1", ([":glob":glob2reg(glob)])); while(row=res->fetch_row()) ret+=({row[0]}); return ret;
a2014e2008-07-14Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! A mapping, indexed on the column name, of mappings describing
a2014e2008-07-14Stephen R. van den Berg //! the attributes of a table of the current database. //! The currently defined fields are: //! //! @mapping
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "schema"
c0f2b72009-04-10Stephen R. van den Berg //! Schema the table belongs to
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "table"
c0f2b72009-04-10Stephen R. van den Berg //! Name of the table
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "kind"
c0f2b72009-04-10Stephen R. van den Berg //! Type of table
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "owner"
c0f2b72009-04-10Stephen R. van den Berg //! Tableowner
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "rowcount"
c0f2b72009-04-10Stephen R. van den Berg //! Estimated rowcount of the table
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "datasize"
c0f2b72009-04-10Stephen R. van den Berg //! Estimated total datasize of the table in bytes
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "indexsize"
c0f2b72009-04-10Stephen R. van den Berg //! Estimated total indexsize of the table in bytes
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "name"
c0f2b72009-04-10Stephen R. van den Berg //! Name of the column
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "type"
c0f2b72009-04-10Stephen R. van den Berg //! A textual description of the internal (to the server) column type-name
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "typeoid"
c0f2b72009-04-10Stephen R. van den Berg //! The OID of the internal (to the server) column type
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member string "length"
c0f2b72009-04-10Stephen R. van den Berg //! Size of the columndatatype
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member mixed "default"
c0f2b72009-04-10Stephen R. van den Berg //! Default value for the column
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "is_shared" //! @member int "has_index"
c0f2b72009-04-10Stephen R. van den Berg //! If the table has any indices
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int "has_primarykey"
c0f2b72009-04-10Stephen R. van den Berg //! If the table has a primary key
a2014e2008-07-14Stephen R. van den Berg //! @endmapping //!
2c228b2009-02-15Stephen R. van den Berg //! @param glob //! If specified, list only the tables with matching names. //! Setting it to @expr{*@} will include system columns in the list.
c0f2b72009-04-10Stephen R. van den Berg array(mapping(string:mixed)) list_fields(void|string table, void|string glob) { array row, ret=({});
a2014e2008-07-14Stephen R. van den Berg  string schema=UNDEFINED; sscanf(table||"*", "%s.%s", schema, table);
98a7762009-02-22Stephen R. van den Berg  object res = big_typed_query(
a2014e2008-07-14Stephen R. van den Berg  "SELECT a.attname, a.atttypid, t.typname, a.attlen, "
98a7762009-02-22Stephen R. van den Berg  " c.relhasindex, c.relhaspkey, CAST(c.reltuples AS BIGINT) AS reltuples, " " (c.relpages " " +COALESCE( " " (SELECT SUM(tst.relpages) " " FROM pg_catalog.pg_class tst " " WHERE tst.relfilenode=c.reltoastrelid) " " ,0) " " )*8192::BIGINT AS datasize, " " (COALESCE( " " (SELECT SUM(pin.relpages) " " FROM pg_catalog.pg_index pi " " JOIN pg_catalog.pg_class pin ON pin.relfilenode=pi.indexrelid " " WHERE pi.indrelid IN (c.relfilenode,c.reltoastrelid)) " " ,0) " " )*8192::BIGINT AS indexsize, "
a2014e2008-07-14Stephen R. van den Berg  " c.relisshared, t.typdefault, " " n.nspname, c.relname, " " CASE c.relkind " " WHEN 'r' THEN 'table' " " WHEN 'v' THEN 'view' " " WHEN 'i' THEN 'index' " " WHEN 'S' THEN 'sequence' " " WHEN 's' THEN 'special' "
7ac2f12008-07-27Stephen R. van den Berg  " WHEN 't' THEN 'toastable' " // pun intended :-)
a2014e2008-07-14Stephen R. van den Berg  " WHEN 'c' THEN 'composite' " " ELSE c.relkind::TEXT END AS relkind, " " r.rolname "
98a7762009-02-22Stephen R. van den Berg  "FROM pg_catalog.pg_class c " " LEFT JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace " " JOIN pg_catalog.pg_roles r ON r.oid=c.relowner " " JOIN pg_catalog.pg_attribute a ON c.oid=a.attrelid " " JOIN pg_catalog.pg_type t ON a.atttypid=t.oid "
a2014e2008-07-14Stephen R. van den Berg  "WHERE c.relname ILIKE :table AND " " (n.nspname ILIKE :schema OR " " :schema IS NULL "
98a7762009-02-22Stephen R. van den Berg  " AND n.nspname<>'pg_catalog' AND n.nspname !~ '^pg_toast') "
2c228b2009-02-15Stephen R. van den Berg  " AND a.attname ILIKE :glob " " AND (a.attnum>0 OR '*'=:realglob) "
a2014e2008-07-14Stephen R. van den Berg  "ORDER BY n.nspname,c.relname,a.attnum,a.attname", ([":schema":glob2reg(schema),":table":glob2reg(table),
2c228b2009-02-15Stephen R. van den Berg  ":glob":glob2reg(glob),":realglob":glob]));
a2014e2008-07-14Stephen R. van den Berg  array colnames=res->fetch_fields(); { mapping(string:string) renames=([ "attname":"name", "nspname":"schema", "relname":"table", "rolname":"owner", "typname":"type", "attlen":"length", "typdefault":"default", "relisshared":"is_shared", "atttypid":"typeoid", "relkind":"kind", "relhasindex":"has_index", "relhaspkey":"has_primarykey", "reltuples":"rowcount", ]);
c0f2b72009-04-10Stephen R. van den Berg  foreach(colnames;int i;mapping m) { string nf,field=m->name;
a2014e2008-07-14Stephen R. van den Berg  if(nf=renames[field])
c0f2b72009-04-10Stephen R. van den Berg  field=nf;
a2014e2008-07-14Stephen R. van den Berg  colnames[i]=field; } } #define delifzero(m,field) if(!(m)[field]) m_delete(m,field)
c0f2b72009-04-10Stephen R. van den Berg  while(row=res->fetch_row()) { mapping m=mkmapping(colnames,row);
a2014e2008-07-14Stephen R. van den Berg  delifzero(m,"is_shared"); delifzero(m,"has_index"); delifzero(m,"has_primarykey"); delifzero(m,"default"); ret+=({m}); } return ret; }
c0f2b72009-04-10Stephen R. van den Berg private int oidformat(int oid) { switch(oid) { case BOOLOID:
a2014e2008-07-14Stephen R. van den Berg  case BYTEAOID: case CHAROID: case INT8OID: case INT2OID: case INT4OID: case TEXTOID: case OIDOID: case XMLOID: case MACADDROID: case BPCHAROID: case VARCHAROID: case CTIDOID: case UUIDOID: return 1; //binary }
c0f2b72009-04-10Stephen R. van den Berg  return 0; // text
a2014e2008-07-14Stephen R. van den Berg }
c0f2b72009-04-10Stephen R. van den Berg final void _sendexecute(int fetchlimit) { string portalname=_c.portal->_portalname;
a2014e2008-07-14Stephen R. van den Berg  PD("Execute portal %s fetchlimit %d\n",portalname,fetchlimit);
7ac2f12008-07-27Stephen R. van den Berg  _c.sendcmd(({"E",_c.plugint32(4+sizeof(portalname)+1+4),portalname,
4741cd2008-07-31Stephen R. van den Berg  "\0",_c.plugint32(fetchlimit)}),!!fetchlimit);
c0f2b72009-04-10Stephen R. van den Berg  if(!fetchlimit) { _c.portal->_fetchlimit=0; // disables further Executes
4741cd2008-07-31Stephen R. van den Berg  earlyclose=1;
c0f2b72009-04-10Stephen R. van den Berg  if(sizeof(portalname)) { PD("Close portal %s & Sync\n",portalname);
4741cd2008-07-31Stephen R. van den Berg  _c.sendcmd(({"C",_c.plugint32(4+1+sizeof(portalname)+1), "P",portalname,"\0"})); } _c.sendcmd(({"S",_c.plugint32(4)}),2); }
80dbe82008-08-08Stephen R. van den Berg  else _c.portal->_inflight+=fetchlimit;
a2014e2008-07-14Stephen R. van den Berg }
c0f2b72009-04-10Stephen R. van den Berg final private void sendclose(void|int hold) { string portalname;
6d42c02010-02-16Stephen R. van den Berg  if(!_c) portalsinflight=unnamedportalinuse=0; else if(_c.portal && (portalname=_c.portal->_portalname))
c0f2b72009-04-10Stephen R. van den Berg  { _c.portal->_portalname = UNDEFINED;
7ac2f12008-07-27Stephen R. van den Berg  _c.setportal();
b133b02008-08-06Stephen R. van den Berg  portalsinflight--;
a2014e2008-07-14Stephen R. van den Berg #ifdef DEBUGMORE PD("Closetrace %O\n",backtrace()); #endif
b212b52008-07-26Stephen R. van den Berg  if(!sizeof(portalname)) unnamedportalinuse--;
c0f2b72009-04-10Stephen R. van den Berg  if(sizeof(portalname)) { if(!earlyclose) { PD("Close portal %s\n",portalname); _c.sendcmd(({"C",_c.plugint32(4+1+sizeof(portalname)+1), "P",portalname,"\0"}),!hold||portalsinflight?1:0);
4741cd2008-07-31Stephen R. van den Berg  } _closesent=1; }
a2014e2008-07-14Stephen R. van den Berg  } }
c0f2b72009-04-10Stephen R. van den Berg final private string trbackendst(int c) { switch(c) { case 'I':return "idle";
a2014e2008-07-14Stephen R. van den Berg  case 'T':return "intransaction"; case 'E':return "infailedtransaction"; }
9287132008-09-03Stephen R. van den Berg  return "";
a2014e2008-07-14Stephen R. van den Berg }
2c228b2009-02-15Stephen R. van den Berg //! @returns //! The current commitstatus of the connection. Returns either one of: //! @string
f4c9d62009-02-15Stephen R. van den Berg //! @value idle //! @value intransaction //! @value infailedtransaction
2c228b2009-02-15Stephen R. van den Berg //! @endstring
a2014e2008-07-14Stephen R. van den Berg //!
2c228b2009-02-15Stephen R. van den Berg //! @note
a2014e2008-07-14Stephen R. van den Berg //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface.
c0f2b72009-04-10Stephen R. van den Berg final string status_commit() { return trbackendst(backendstatus);
a2014e2008-07-14Stephen R. van den Berg }
c0f2b72009-04-10Stephen R. van den Berg final private array(string) closestatement(mapping tp) { string oldprep=tp->preparedname;
24ea552009-02-12Stephen R. van den Berg  array(string) ret=({});
c0f2b72009-04-10Stephen R. van den Berg  if(oldprep) { PD("Close statement %s\n",oldprep);
24ea552009-02-12Stephen R. van den Berg  ret=({"C",_c.plugint32(4+1+sizeof(oldprep)+1),
d1a5a42008-08-27Stephen R. van den Berg  "S",oldprep,"\0"}); }
24ea552009-02-12Stephen R. van den Berg  return ret;
d1a5a42008-08-27Stephen R. van den Berg }
0412962009-01-19Stephen R. van den Berg //! @decl Sql.pgsql_util.pgsql_result big_query(string query) //! @decl Sql.pgsql_util.pgsql_result big_query(string query, mapping bindings) //!
a2014e2008-07-14Stephen R. van den Berg //! This is the only provided interface which allows you to query the
f4c9d62009-02-15Stephen R. van den Berg //! database. If you wish to use the simpler @[Sql.Sql()->query()] function, //! you need to use the @[Sql.Sql] generic SQL-object.
a2014e2008-07-14Stephen R. van den Berg //!
f4c9d62009-02-15Stephen R. van den Berg //! Bindings are supported natively straight across the network.
2c228b2009-02-15Stephen R. van den Berg //! Special bindings supported are: //! @mapping
13d29c2009-04-16Henrik Grubbström (Grubba) //! @member int ":_cache"
f4c9d62009-02-15Stephen R. van den Berg //! Forces caching on or off for the query at hand.
02dfd22012-04-06Stephen R. van den Berg //! @member int ":_text" //! Forces text mode in communication with the database for queries on or off //! for the query at hand. Potentially more efficient than the default //! binary method for simple queries with small or no result sets.
2c228b2009-02-15Stephen R. van den Berg //! @endmapping //! //! @returns //! A @[Sql.pgsql_util.pgsql_result] object (which conforms to the
f4c9d62009-02-15Stephen R. van den Berg //! @[Sql.sql_result] standard interface for accessing data). It is //! recommended to use @[Sql.Sql()->query()] for simpler queries (because //! it is easier to handle, but stores all the result in memory), and //! @[Sql.Sql()->big_query()] for queries you expect to return huge amounts of
a2014e2008-07-14Stephen R. van den Berg //! data (it's harder to handle, but fetches results on demand). //! //! @note //! This function @b{can@} raise exceptions. //!
17b7532008-07-30Stephen R. van den Berg //! @note
2c228b2009-02-15Stephen R. van den Berg //! This function supports multiple simultaneous queries (portals) on a single //! database connection. This is a feature not commonly supported by other //! database backends. //! //! @note
02dfd22012-04-06Stephen R. van den Berg //! This function, by default, does not support multiple queries in one //! querystring.
17b7532008-07-30Stephen R. van den Berg //! I.e. it allows for but does not require a trailing semicolon, but it
f4c9d62009-02-15Stephen R. van den Berg //! simply ignores any commands after the first unquoted semicolon. This can //! be viewed as a limited protection against SQL-injection attacks.
02dfd22012-04-06Stephen R. van den Berg //! To make it support multiple queries in one querystring, use the //! @ref{:_text@} option.
17b7532008-07-30Stephen R. van den Berg //!
a2014e2008-07-14Stephen R. van den Berg //! @seealso
f4c9d62009-02-15Stephen R. van den Berg //! @[big_typed_query()], @[Sql.Sql], @[Sql.sql_result], //! @[Sql.Sql()->query()], @[Sql.pgsql_util.pgsql_result]
b156722008-08-25Stephen R. van den Berg object big_query(string q,void|mapping(string|int:mixed) bindings,
c0f2b72009-04-10Stephen R. van den Berg  void|int _alltyped) { string preparedname="";
a2014e2008-07-14Stephen R. van den Berg  string portalname="";
80dbe82008-08-08Stephen R. van den Berg  int forcecache=-1;
02dfd22012-04-06Stephen R. van den Berg  int forcetext=options->text_query;
26c0ad2009-02-28Stephen R. van den Berg  string cenc=_runtimeparameter[CLIENT_ENCODING]; switch(cenc) { case UTF8CHARSET: q=string_to_utf8(q); break; default: if(String.width(q)>8)
c0f2b72009-04-10Stephen R. van den Berg  ERROR("Don't know how to convert %O to %s encoding\n",q,cenc);
26c0ad2009-02-28Stephen R. van den Berg  }
a2014e2008-07-14Stephen R. van den Berg  array(string|int) paramValues;
c8942c2009-04-10Stephen R. van den Berg  array from;
c0f2b72009-04-10Stephen R. van den Berg  if(bindings) { int pi=0,rep=0;
a2014e2008-07-14Stephen R. van den Berg  paramValues=allocate(sizeof(bindings));
11e81e2009-02-13Stephen R. van den Berg  from=allocate(sizeof(bindings));
c8942c2009-04-10Stephen R. van den Berg  array(string) to=allocate(sizeof(bindings));
c0f2b72009-04-10Stephen R. van den Berg  foreach(bindings; mixed name; mixed value) { if(stringp(name)) // Throws if mapping key is empty string { if(name[0]!=':') name=":"+name; if(name[1]=='_') // Special option parameter { switch(name) { case ":_cache":forcecache=(int)value;
80dbe82008-08-08Stephen R. van den Berg  break;
02dfd22012-04-06Stephen R. van den Berg  case ":_text":forcetext=(int)value; break;
80dbe82008-08-08Stephen R. van den Berg  }
c0f2b72009-04-10Stephen R. van den Berg  continue; }
9b6a8b2009-01-12Stephen R. van den Berg  if(!has_value(q,name))
565d982008-08-27Stephen R. van den Berg  continue;
a2014e2008-07-14Stephen R. van den Berg  } from[rep]=name; string rval;
26c0ad2009-02-28Stephen R. van den Berg  if(multisetp(value)) // multisets are taken literally
c0f2b72009-04-10Stephen R. van den Berg  rval=indices(value)*","; // and bypass the encoding logic
26c0ad2009-02-28Stephen R. van den Berg  else { paramValues[pi++]=value;
c0f2b72009-04-10Stephen R. van den Berg  rval=sprintf("$%d",pi);
a2014e2008-07-14Stephen R. van den Berg  } to[rep++]=rval; } if(rep--)
11e81e2009-02-13Stephen R. van den Berg  q=replace(q,from=from[..rep],to=to[..rep]);
a2014e2008-07-14Stephen R. van den Berg  paramValues= pi ? paramValues[..pi-1] : ({});
c8942c2009-04-10Stephen R. van den Berg  from=({from,to,paramValues});
a2014e2008-07-14Stephen R. van den Berg  } else paramValues = ({});
26c0ad2009-02-28Stephen R. van den Berg  if(String.width(q)>8) ERROR("Wide string literals in %O not supported\n",q);
8a4ac42009-01-24Stephen R. van den Berg  if(has_value(q,"\0")) ERROR("Querystring %O contains invalid literal nul-characters\n",q);
cb26232008-08-04Stephen R. van den Berg  mapping(string:mixed) tp;
a2014e2008-07-14Stephen R. van den Berg  int tstart;
02dfd22012-04-06Stephen R. van den Berg  if(forcetext) { if(bindings) q = .sql_util.emulate_bindings(q, bindings, this); if(unnamedportalinuse) throw("Unnamed portal in use, needed for simple query"); } else if(forcecache==1
7bca1b2012-04-04Stephen R. van den Berg  || forcecache!=0 && (sizeof(q)>=MINPREPARELENGTH || cachealways[q]))
c0f2b72009-04-10Stephen R. van den Berg  { array(string) plugbuf=({}); if(tp=prepareds[q]) { if(tp->preparedname) prepstmtused++, preparedname=tp->preparedname;
cb26232008-08-04Stephen R. van den Berg  else if((tstart=tp->trun)
758a052008-09-02Stephen R. van den Berg  && tp->tparse*FACTORPLAN>=tstart && (zero_type(options->cache_autoprepared_statements)
c0f2b72009-04-10Stephen R. van den Berg  || options->cache_autoprepared_statements))
a2014e2008-07-14Stephen R. van den Berg  preparedname=PREPSTMTPREFIX+(string)pstmtcount++; }
c0f2b72009-04-10Stephen R. van den Berg  else { if(totalhits>=cachedepth) { foreach(prepareds;string ind;tp) { int oldhits=tp->hits;
cb26232008-08-04Stephen R. van den Berg  totalhits-=oldhits-(tp->hits=oldhits>>1);
c0f2b72009-04-10Stephen R. van den Berg  if(oldhits<=1) { plugbuf+=closestatement(tp);
a2014e2008-07-14Stephen R. van den Berg  m_delete(prepareds,ind); }
c0f2b72009-04-10Stephen R. van den Berg  }
a2014e2008-07-14Stephen R. van den Berg  }
d1a5a42008-08-27Stephen R. van den Berg  if(forcecache!=1 && createprefix->match(q)) // Flush cache on CREATE
a6a8e32010-02-14Stephen R. van den Berg  invalidatecache=1,tp=UNDEFINED;
d1a5a42008-08-27Stephen R. van den Berg  else
c0f2b72009-04-10Stephen R. van den Berg  prepareds[q]=tp=([]);
a2014e2008-07-14Stephen R. van den Berg  }
c0f2b72009-04-10Stephen R. van den Berg  if(invalidatecache) { invalidatecache=0; foreach(prepareds;;mapping np) { plugbuf+=closestatement(np); m_delete(np,"preparedname");
d1a5a42008-08-27Stephen R. van den Berg  } }
c0f2b72009-04-10Stephen R. van den Berg  if(sizeof(plugbuf)) { _c.sendcmd(plugbuf,1); // close expireds
d1a5a42008-08-27Stephen R. van den Berg  PD("%O\n",plugbuf); }
a2014e2008-07-14Stephen R. van den Berg  tstart=gethrtime();
7ac2f12008-07-27Stephen R. van den Berg  } // pgsql_result autoassigns to portal
cb26232008-08-04Stephen R. van den Berg  else tp=UNDEFINED;
bac80c2010-02-15Stephen R. van den Berg  connectionclosed=0; for(;;)
02dfd22012-04-06Stephen R. van den Berg  { .pgsql_util.pgsql_result(this,q,_fetchlimit, portalbuffersize,_alltyped,from,forcetext);
0790222010-02-15Stephen R. van den Berg  if(unnamedportalinuse) portalname=PORTALPREFIX+(string)pportalcount++; else unnamedportalinuse++; _c.portal->_portalname=portalname; qstate=inquery; portalsinflight++; portalsopened++; clearmessage=1; mixed err; if(!(err = catch
02dfd22012-04-06Stephen R. van den Berg  { if(forcetext) { _c.sendcmd(({"Q",_c.plugint32(4+sizeof(q)+1),q,"\0"}),1); PD("Simple query: %O\n",q);
488ce72008-07-24Stephen R. van den Berg  }
c0f2b72009-04-10Stephen R. van den Berg  else
02dfd22012-04-06Stephen R. van den Berg  { if(!sizeof(preparedname) || !tp || !tp->preparedname) { PD("Parse statement %s\n",preparedname); // Even though the protocol doesn't require the Parse command to be // followed by a flush, it makes a VERY noticeable difference in // performance if it is omitted; seems like a flaw in the PostgreSQL // server v8.3.3 _c.sendcmd(({"P",_c.plugint32(4+sizeof(preparedname)+1+sizeof(q)+1+2), preparedname,"\0",q,"\0",_c.plugint16(0)}),3); PD("Query: %O\n",q); } // sends Parameter- and RowDescription for 'S' if(!tp || !tp->datatypeoid) { PD("Describe statement %s\n",preparedname); _c.sendcmd(({"D",_c.plugint32(4+1+sizeof(preparedname)+1), "S",preparedname,"\0"}),1); } else { skippeddescribe++; _c.portal->_datatypeoid=tp->datatypeoid; _c.portal->_datarowdesc=tp->datarowdesc; } { array(string) plugbuf=({"B",UNDEFINED}); int len=4+sizeof(portalname)+1+sizeof(preparedname)+1 +2+sizeof(paramValues)*(2+4)+2+2; plugbuf+=({portalname,"\0",preparedname,"\0", _c.plugint16(sizeof(paramValues))}); if(!tp || !tp->datatypeoid) { _decodemsg(gotparameterdescription); if(tp) tp->datatypeoid=_c.portal->_datatypeoid; } array dtoid=_c.portal->_datatypeoid; if(sizeof(dtoid)!=sizeof(paramValues)) USERERROR( sprintf("Invalid number of bindings, expected %d, got %d\n", sizeof(dtoid),sizeof(paramValues))); foreach(dtoid;;int textbin) plugbuf+=({_c.plugint16(oidformat(textbin))}); plugbuf+=({_c.plugint16(sizeof(paramValues))}); foreach(paramValues;int i;mixed value) { if(zero_type(value)) plugbuf+=({_c.plugint32(-1)}); // NULL else if(stringp(value) && !sizeof(value)) { int k=0; switch(dtoid[i]) { default: k=-1; // cast empty strings to NULL for non-string types case BYTEAOID: case TEXTOID: case XMLOID: case BPCHAROID: case VARCHAROID:; } plugbuf+=({_c.plugint32(k)}); } else switch(dtoid[i]) { case TEXTOID: case BPCHAROID: case VARCHAROID: { if(!value) { plugbuf+=({_c.plugint32(-1)}); break; } value=(string)value; switch(cenc) { case UTF8CHARSET: value=string_to_utf8(value); break; default: if(String.width(value)>8) ERROR("Don't know how to convert %O to %s encoding\n", value,cenc); } int k; len+=k=sizeof(value); plugbuf+=({_c.plugint32(k),value}); break; } default: { int k; if(!value) { plugbuf+=({_c.plugint32(-1)}); break; } value=(string)value; if(String.width(value)>8) if(dtoid[i]==BYTEAOID) value=string_to_utf8(value); else ERROR("Wide string %O not supported for type OID %d\n", value,dtoid[i]); len+=k=sizeof(value); plugbuf+=({_c.plugint32(k),value}); break; } case BOOLOID:plugbuf+=({_c.plugint32(1)});len++; do { int tval; if(stringp(value)) tval=value[0]; else if(!intp(value)) { value=!!value; // cast to boolean break; } else tval=value; switch(tval) { case 'o':case 'O': catch { tval=value[1]; value=tval=='n'||tval=='N'; }; break; default: value=1; break; case 0:case 'f':case 'F':case 'n':case 'N': value=0; break; } } while(0); plugbuf+=({_c.plugbyte(value)}); break; case CHAROID: if(intp(value)) len++,plugbuf+=({_c.plugint32(1),_c.plugbyte(value)}); else { value=(string)value; switch(sizeof(value)) { default: ERROR("\"char\" types must be 1 byte wide, got %O\n", value); case 0: plugbuf+=({_c.plugint32(-1)}); // NULL break; case 1:len++; plugbuf+=({_c.plugint32(1),_c.plugbyte(value[0])}); } } break; case INT8OID:len+=8; plugbuf+=({_c.plugint32(8),_c.plugint64((int)value)}); break; case OIDOID: case INT4OID:len+=4; plugbuf+=({_c.plugint32(4),_c.plugint32((int)value)}); break; case INT2OID:len+=2; plugbuf+=({_c.plugint32(2),_c.plugint16((int)value)}); break; } } if(!tp || !tp->datarowdesc) { if(tp && dontcacheprefix->match(q)) // Don't cache FETCH/COPY m_delete(prepareds,q),tp=0; _decodemsg(gotrowdescription); if(tp) tp->datarowdesc=_c.portal->_datarowdesc; } { array a;int i; len+=(i=sizeof(a=_c.portal->_datarowdesc))*2; plugbuf+=({_c.plugint16(i)}); foreach(a;;mapping col) plugbuf+=({_c.plugint16(oidformat(col->type))}); } plugbuf[1]=_c.plugint32(len); PD("Bind portal %s statement %s\n",portalname,preparedname); _c.sendcmd(plugbuf); #ifdef DEBUGMORE PD("%O\n",plugbuf);
a2014e2008-07-14Stephen R. van den Berg #endif
02dfd22012-04-06Stephen R. van den Berg  } _c.portal->_statuscmdcomplete=UNDEFINED; _sendexecute(_fetchlimit && !(cachealways[q] || sizeof(q)>=MINPREPARELENGTH && execfetchlimit->match(q)) && FETCHLIMITLONGRUN); if(tp) { _decodemsg(bindcomplete); int tend=gethrtime(); if(tend==tstart) m_delete(prepareds,q); else { tp->hits++; totalhits++; if(!tp->preparedname) { if(sizeof(preparedname)) tp->preparedname=preparedname; tstart=tend-tstart; if(!tp->tparse || tp->tparse>tstart) tp->tparse=tstart; } tp->trunstart=tend; } tprepared=tp; }
a2014e2008-07-14Stephen R. van den Berg  }
bac80c2010-02-15Stephen R. van den Berg  }))
0790222010-02-15Stephen R. van den Berg  break; PD("%O\n",err); resync(1); backendstatus=UNDEFINED; if(!connectionclosed) throw(err); tp=UNDEFINED;
a2014e2008-07-14Stephen R. van den Berg  }
c0f2b72009-04-10Stephen R. van den Berg  { object tportal=_c.portal; // Make copy, because it might dislodge tportal->fetch_row(1); // upon initial fetch_row()
a2014e2008-07-14Stephen R. van den Berg  return tportal; } } //! This is an alias for @[big_query()], since @[big_query()] already supports //! streaming of multiple simultaneous queries through the same connection. //! //! @seealso
f4c9d62009-02-15Stephen R. van den Berg //! @[big_query()], @[big_typed_query()], @[Sql.Sql], @[Sql.sql_result]
c0f2b72009-04-10Stephen R. van den Berg object streaming_query(string q,void|mapping(string|int:mixed) bindings) { return big_query(q,bindings);
a2014e2008-07-14Stephen R. van den Berg }
b156722008-08-25Stephen R. van den Berg  //! This function returns an object that allows streaming and typed //! results. //! //! @seealso
2c228b2009-02-15Stephen R. van den Berg //! @[big_query()], @[Sql.Sql], @[Sql.sql_result]
c0f2b72009-04-10Stephen R. van den Berg object big_typed_query(string q,void|mapping(string|int:mixed) bindings) { return big_query(q,bindings,1);
b156722008-08-25Stephen R. van den Berg }