pike.git/lib/modules/Sql.pmod/pgsql.pike:65:
int _nextportal;
int _closesent;
int _fetchlimit=FETCHLIMIT;
private int unnamedportalinuse;
private int portalsinflight;
private object conn;
private string SSauthdata,cancelsecret;
private int backendpid;
private int backendstatus;
+ private mapping(string:mixed) options;
private string lastmessage;
private mapping(string:array(mixed)) notifylist=([]);
private mapping(string:string) msgresponse;
private mapping(string:string) runtimeparameter;
private enum state {unauthenticated,authenticated,readyforquery,
parsecomplete,bindcomplete,commandcomplete,gotrowdescription,
gotparameterdescription,dataready,dataprocessed,portalsuspended,
copyinresponse};
private state mstate;
private enum querystate {queryidle,inquery,cancelpending,canceled};
pike.git/lib/modules/Sql.pmod/pgsql.pike:86:
private mapping(string:mapping(string:mixed)) prepareds=([]);
private int pstmtcount;
private int pportalcount;
private int totalhits;
private int cachedepth=1024; // Maximum cachecountsum for prepared statements,
// may be tuned by the application
private int timeout=4096; // Queries running longer than this number of
// seconds are canceled automatically
private int portalbuffersize=32*1024; // Approximate buffer per portal
private int reconnected; // Number of times the connection was reset
- #ifndef USEPGsql
- private int flushed;
- #endif
+
private string host, database, user, pass;
private int port;
private mapping(string:string) sessiondefaults=([]); // runtime parameters
private Thread.Mutex querymutex;
private Thread.Mutex stealmutex;
protected string _sprintf(int type, void|mapping flags) {
string res=UNDEFINED;
switch(type) {
pike.git/lib/modules/Sql.pmod/pgsql.pike:139:
#define BPCHAROID 1042
#define VARCHAROID 1043
#define CTIDOID 1247
#define UUIDOID 2950
#define PG_PROTOCOL(m,n) (((m)<<16)|(n))
#define FLUSH "H\0\0\0\4"
//! @decl void create()
//! @decl void create(string host, void|string database, void|string user,@
- //! void|string password)
+ //! void|string password, void|mapping(string:mixed) options)
//!
//! With no arguments, this function initializes (reinitializes if a
//! connection had been previously set up) a connection to the
//! PostgreSQL backend. Since PostgreSQL requires a database to be
//! selected, it will try to connect to the default database. The
//! connection may fail however for a variety of reasons, in this case
//! the most likely of all is because you don't have enough authority
//! to connect to that database. So use of this particular syntax is
//! discouraged.
//!
pike.git/lib/modules/Sql.pmod/pgsql.pike:169:
//! @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
//! @[Postgres.postgres], @[Sql.Sql], @[postgres->select_db]
protected void create(void|string _host, void|string _database,
- void|string _user, void|string _pass) {
+ void|string _user, void|string _pass, void|mapping(string:mixed) _options) {
pass = _pass; _pass = "CENSORED";
user = _user; database = _database; host = _host || PGSQL_DEFAULT_HOST;
-
+ options = _options;
if(search(host,":")>=0 && sscanf(_host,"%s:%d",host,port)!=2)
ERROR("Error in parsing the hostname argument\n");
if(!port)
port = PGSQL_DEFAULT_PORT;
querymutex=Thread.Mutex();
stealmutex=Thread.Mutex();
reconnect();
}
//! @decl string error()
pike.git/lib/modules/Sql.pmod/pgsql.pike:208:
//! @decl string host_info()
//!
//! This function returns a string describing what host are we talking to,
//! and how (TCP/IP or UNIX sockets).
string host_info() {
return sprintf("Via fd:%d over TCP/IP to %s:%d",conn->query_fd(),host,port);
}
- #ifdef USEPGsql
+ #define SENDCMD(x ...) conn.sendcmd(x)
#define GETBYTE() conn.getbyte()
#define GETSTRING(x) conn.getstring(x)
#define GETINT16() conn.getint16()
#define GETINT32() conn.getint32()
#define FLUSHED conn.flushed
-
+
+ #ifdef USEPGsql
+ #define PEEK(x) conn.bpeek(x)
#else
- #define GETBYTE() getbyte()
- #define GETSTRING(x) getstring(x)
- #define GETINT16() getint16()
- #define GETINT32() getint32()
- #define FLUSHED flushed
+ #define PEEK(x) conn.peek(x)
- final private void sendflush() {
- SENDCMD(({}),1);
+ #endif
+
+ #define plugstring(x) (sprintf x)
+
+ #define plugbyte(x) sprintf("%c",x)
+
+ inline final private string plugint16(int x) {
+ return sprintf("%c%c",x>>8&255,x&255);
}
- inline final private int getbyte() {
- if(!FLUSHED && !conn.peek(0))
+ inline final private string plugint32(int x) {
+ return sprintf("%c%c%c%c",x>>24&255,x>>16&255,x>>8&255,x&255);
+ }
+
+ inline final private string plugint64(int x) {
+ return sprintf("%c%c%c%c%c%c%c%c",
+ x>>56&255,x>>48&255,x>>40&255,x>>32&255,x>>24&255,x>>16&255,x>>8&255,x&255);
+ }
+
+ class PGassist {
+ #ifdef UNBUFFEREDIO
+ inherit Stdio.File:std;
+ #else
+ inherit Stdio.FILE:std;
+ #endif
+ #ifdef USEPGsql
+ inherit _PGsql.PGsql:pg;
+ #else
+ int flushed;
+ #endif
+ void create(object pgsqlsess) {
+ std::create();
+ #ifdef USEPGsql
+ pg::setpgsqlsess(pgsqlsess);
+ #else
+ flushed=-1;
+ #endif
+ }
+ int connect(string host,int port) {
+ int res=std::connect(host,port);
+ #ifdef USEPGsql
+ if(res)
+ pg::create(std::query_fd());
+ #endif
+ return res;
+ }
+
+ #ifndef USEPGsql
+
+ inline final int getbyte() {
+ if(!FLUSHED && !PEEK(0))
sendflush();
#ifdef UNBUFFEREDIO
- return conn.read(1)[0];
+ return read(1)[0];
#else
- return conn.getchar();
+ return getchar();
#endif
}
- final private string getstring(void|int len) {
+ final string getstring(void|int len) {
if(!zero_type(len)) {
string acc="",res;
do {
- if(!FLUSHED && !conn.peek(0))
+ if(!FLUSHED && !PEEK(0))
sendflush();
res=conn.read(len,!FLUSHED);
if(res) {
if(!sizeof(res))
return acc;
acc+=res;
}
}
while(sizeof(acc)<len&&res);
return sizeof(acc)?acc:res;
}
array(int) acc=({});
int c;
while((c=GETBYTE())>0)
acc+=({c});
return `+("",@map(acc,String.int2char));
}
- inline final private int getint16() {
+ inline final int getint16() {
int s0=GETBYTE();
int r=(s0&0x7f)<<8|GETBYTE();
return s0&0x80 ? r-(1<<15) : r ;
}
- inline final private int getint32() {
+ inline final int getint32() {
int r=GETINT16();
r=r<<8|GETBYTE();
return r<<8|GETBYTE();
}
- inline final private int getint64() {
+ inline final int getint64() {
int r=GETINT32();
return r<<32|GETINT32()&0xffffffff;
}
#endif
- #define SENDCMD(x ...) sendcmd(x)
+ final protected void sendflush() {
+ sendcmd(({}),1);
+ }
- final private int sendcmd(string|array(string) data,void|int flush) {
+ final int sendcmd(string|array(string) data,void|int flush) {
if(flush) {
if(stringp(data))
data=({data,FLUSH});
else
data+=({FLUSH});
PD("Flush\n");
FLUSHED=1;
}
else if(FLUSHED!=-1)
FLUSHED=0;
- return conn.write(data);
+ return write(data);
}
-
- #define plugstring(x) (sprintf x)
-
- #define plugbyte(x) sprintf("%c",x)
-
- inline final private string plugint16(int x) {
- return sprintf("%c%c",x>>8&255,x&255);
+
}
- inline final private string plugint32(int x) {
- return sprintf("%c%c%c%c",x>>24&255,x>>16&255,x>>8&255,x&255);
- }
-
- inline final private string plugint64(int x) {
- return sprintf("%c%c%c%c%c%c%c%c",
- x>>56&255,x>>48&255,x>>40&255,x>>32&255,x>>24&255,x>>16&255,x>>8&255,x&255);
- }
-
- #ifdef USEPGsql
- class PGassist {
- inherit Stdio.File:std;
- inherit _PGsql.PGsql:pg;
- void create(object pgsqlsess) {
- std::create();
- pg::setpgsqlsess(pgsqlsess);
- }
- int connect(string host,int port) {
- int res=std::connect(host,port);
- if(res)
- pg::create(std::query_fd());
- return res;
- }
- }
- #endif
-
+
final private object getsocket() {
- #ifdef USEPGsql
+
object lcon = PGassist(this);
- #else
- #ifdef UNBUFFEREDIO
- object lcon = Stdio.File();
- #else
- object lcon = Stdio.FILE();
+ if(!lcon.connect(host,port))
+ return UNDEFINED;
+ #if constant(SSL.sslfile)
+ #if 0
+ SSL.context context = SSL.context();
+ #if 1
+ context->preferred_suites = ({
+ SSL_rsa_with_idea_cbc_sha,
+ SSL_rsa_with_rc4_128_sha,
+ SSL_rsa_with_rc4_128_md5,
+ SSL_rsa_with_3des_ede_cbc_sha,
+ SSL_rsa_export_with_rc4_40_md5,
+ SSL_rsa_export_with_rc2_cbc_40_md5,
+ SSL_rsa_export_with_des40_cbc_sha,
+ });
#endif
- flushed=-1;
+ context->random = Crypto.Random.random_string;
+ object read_callback=con->query_read_callback();
+ object write_callback=con->query_write_callback();
+ object close_callback=con->query_close_callback();
+
+ ssl = SSL.sslfile(con, context, 1,blocking);
+ if(!blocking) {
+ ssl->set_read_callback(read_callback);
+ ssl->set_write_callback(write_callback);
+ ssl->set_close_callback(close_callback);
+ }
+ con=ssl;
#endif
- return lcon.connect(host,port) && lcon;
+ #endif
+ return lcon;
}
//! Cancels the currently running query.
//!
//! This function is PostgreSQL-specific, and thus it is not available
//! through the generic SQL-interface.
void cancelquery() {
if(qstate==inquery) {
qstate=cancelpending;
object lcon;
pike.git/lib/modules/Sql.pmod/pgsql.pike:437: Inside #if defined(DEBUG) and #if defined(DEBUGMORE)
#ifdef DEBUGMORE
line=backtrace();
#endif
PD("Waiting for state %O %O\n",waitforstate,line&&line[sizeof(line)-2]);
}
#endif
while(mstate!=waitforstate) {
if(mstate!=unauthenticated) {
if(qstate==cancelpending)
qstate=canceled,sendclose();
- if(FLUSHED && qstate==inquery && !conn.peek(0)) {
+ if(FLUSHED && qstate==inquery && !PEEK(0)) {
int tcurr=time();
int told=tcurr+timeout;
- while(!conn.peek(told-tcurr))
+ while(!PEEK(told-tcurr))
if((tcurr=time())-told>=timeout) {
sendclose();cancelquery();
break;
}
}
}
int msgtype=GETBYTE();
int msglen=GETINT32();
enum errortype { noerror=0, protocolerror, protocolunsupported };
errortype errtype=noerror;
pike.git/lib/modules/Sql.pmod/pgsql.pike:651:
int collen=GETINT32();
if(collen>0) {
msglen-=collen;
mixed value;
switch(datarowdesc[i]->type) {
default:value=GETSTRING(collen);
break;
case CHAROID:
case BOOLOID:value=GETBYTE();
break;
- case INT8OID:value=getint64();
+ case INT8OID:value=conn.getint64();
break;
case FLOAT4OID:value=(float)GETSTRING(collen);
break;
case INT2OID:value=GETINT16();
break;
case OIDOID:
case INT4OID:value=GETINT32();
}
a[i]=value;
}
pike.git/lib/modules/Sql.pmod/pgsql.pike:800:
break;
}
PD("Found state %O\n",mstate);
return mstate;
}
#ifndef UNBUFFEREDIO
private int read_cb(mixed foo, string d) {
conn.unread(d);
do _decodemsg();
- while(conn.peek(0)==1);
+ while(PEEK(0)==1);
return 0;
}
#endif
final private void sendterminate() {
PD("Terminate\n");
SENDCMD(({"X",plugint32(4)}));
conn.close();
}
pike.git/lib/modules/Sql.pmod/pgsql.pike:1320:
portalname=PORTALPREFIX+(string)pportalcount++;
else
unnamedportalinuse++;
_portal->_portalname=portalname;
qstate=inquery;
portalsinflight++;
mixed err;
if(err = catch {
if(!sizeof(preparedname) || !tprepared || !tprepared->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
SENDCMD(({"P",plugint32(4+sizeof(preparedname)+1+sizeof(q)+1+2),
preparedname,"\0",q,"\0",plugint16(0)}),1);
PD("Query: %O\n",q);
} // sends Parameter- and RowDescription for 'S'
conn.set_read_callback(0);
if(!tprepared || !tprepared->datatypeoid) {
PD("Describe statement %s\n",preparedname);
SENDCMD(({"D",plugint32(4+1+sizeof(preparedname)+1),
"S",preparedname,"\0"}),1);
}