pike.git/lib/modules/Sql.pmod/pgsql.pike:26: Inside #if defined(DEBUG)
#ifdef DEBUG
#define PD(X ...) werror(X)
#define UNBUFFEREDIO 1 // Make all IO unbuffered
#else
#undef DEBUGMORE
#define PD(X ...)
#endif
//#define NO_LOCKING 1 // This breaks the driver, do not enable,
// only for benchmarking mutex performance
+ #define USEPGsql 1 // Doesn't use Stdio.FILE, but PG assist
-
+ #ifdef USEPGsql
+ #define UNBUFFEREDIO 1
+ #endif
+
#define FETCHLIMIT 1024 // Initial upper limit on the
// number of rows to fetch across the
// network at a time
// 0 for no chunking
// Needs to be >0 for interleaved
// portals
#define FETCHLIMITLONGRUN 1 // for long running background queries
#define STREAMEXECUTES 1 // streams executes if defined
- #define MINPREPARELENGTH 64 // statements shorter than this will not
+ #define MINPREPARELENGTH 16 // statements shorter than this will not
// be cached
#define PGSQL_DEFAULT_PORT 5432
#define PGSQL_DEFAULT_HOST "localhost"
#define PREPSTMTPREFIX "pike_prep_"
#define PORTALPREFIX "pike_portal_"
#define FACTORPLAN 8
#define DRIVERNAME "pgsql"
#define MARKSTART "{""{""{""{\n" // split string to avoid
#define MARKERROR ">>>>" // foldeditors from recognising
#define MARKEND "\n}""}""}""}" // it as a fold
pike.git/lib/modules/Sql.pmod/pgsql.pike:81:
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=64*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:201:
//! @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);
}
- final private 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
- flushed=0;
- return conn.write(data);
- }
+ #ifdef USEPGsql
+ #define GETBYTE() conn.getbyte()
+ #define GETSTRING(x) conn.getstring(x)
+ #define GETINT16() conn.getint16()
+ #define GETINT32() conn.getint32()
+ #define FLUSHED conn.flushed
+ #else
+ #define GETBYTE() getbyte()
+ #define GETSTRING(x) getstring(x)
+ #define GETINT16() getint16()
+ #define GETINT32() getint32()
+ #define FLUSHED flushed
final private void sendflush() {
- sendcmd(({}),1);
+ SENDCMD(({}),1);
}
inline final private int getbyte() {
- if(!flushed && !conn.peek(0))
+ if(!FLUSHED && !conn.peek(0))
sendflush();
#ifdef UNBUFFEREDIO
return conn.read(1)[0];
#else
return conn.getchar();
#endif
}
- final private string getstring(int len) {
+ final private string getstring(void|int len) {
+ if(!zero_type(len)) {
string acc="",res;
do {
- if(!flushed && !conn.peek(0))
+ if(!FLUSHED && !conn.peek(0))
sendflush();
- res=conn.read(len,!flushed);
+ 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() {
- int s0=getbyte();
- int r=(s0&0x7f)<<8|getbyte();
+ int s0=GETBYTE();
+ int r=(s0&0x7f)<<8|GETBYTE();
return s0&0x80 ? r-(1<<15) : r ;
}
inline final private int getint32() {
- int r=getint16();
- r=r<<8|getbyte();
- return r<<8|getbyte();
+ int r=GETINT16();
+ r=r<<8|GETBYTE();
+ return r<<8|GETBYTE();
}
inline final private int getint64() {
- int r=getint32();
- r=r<<8|getbyte();
- r=r<<8|getbyte();
- r=r<<8|getbyte();
- return r<<8|getbyte();
+ int r=GETINT32();
+ return r<<32|GETINT32()&0xffffffff;
}
-
+ #endif
-
+ #define SENDCMD(x ...) sendcmd(x)
+
+ final private 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);
+ }
+
#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() {
+ std::create();
+ }
+ 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();
+ #else
#ifdef UNBUFFEREDIO
object lcon = Stdio.File();
#else
object lcon = Stdio.FILE();
#endif
-
+ flushed=-1;
+ #endif
return lcon.connect(host,port) && 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;
pike.git/lib/modules/Sql.pmod/pgsql.pike:315:
}
}
//! Returns the old cachedepth, sets the new cachedepth for prepared
//! statements automatic caching.
//!
//! This function is PostgreSQL-specific, and thus it is not available
//! through the generic SQL-interface.
int setcachedepth(void|int newdepth) {
int olddepth=cachedepth;
- if(intp(newdepth) && newdepth>=0)
+ if(!zero_type(newdepth) && newdepth>=0)
cachedepth=newdepth;
return olddepth;
}
//! Returns the old timeout, sets the new timeout for long running
//! queries.
//!
//! This function is PostgreSQL-specific, and thus it is not available
//! through the generic SQL-interface.
int settimeout(void|int newtimeout) {
int oldtimeout=timeout;
- if(intp(newtimeout) && newtimeout>0)
+ if(!zero_type(newtimeout) && newtimeout>0)
timeout=newtimeout;
return oldtimeout;
}
//! Returns the old portalbuffersize, sets the new portalbuffersize
//! for buffering partially concurrent queries.
//!
//! This function is PostgreSQL-specific, and thus it is not available
//! through the generic SQL-interface.
int setportalbuffersize(void|int newportalbuffersize) {
int oldportalbuffersize=portalbuffersize;
- if(intp(newportalbuffersize) && newportalbuffersize>0)
+ if(!zero_type(newportalbuffersize) && newportalbuffersize>0)
portalbuffersize=newportalbuffersize;
return oldportalbuffersize;
}
//! Returns the old fetchlimit, sets the new fetchlimit to interleave
//! queries.
//!
//! This function is PostgreSQL-specific, and thus it is not available
//! through the generic SQL-interface.
int setfetchlimit(void|int newfetchlimit) {
int oldfetchlimit=_fetchlimit;
- if(intp(newfetchlimit) && newfetchlimit>=0)
+ if(!zero_type(newfetchlimit) && newfetchlimit>=0)
_fetchlimit=newfetchlimit;
return oldfetchlimit;
}
final private string glob2reg(string glob) {
if (!glob||!sizeof(glob))
return "%";
return replace(glob,({"*","?","\\","%","_"}),({"%","_","\\\\","\\%","\\_"}));
}
pike.git/lib/modules/Sql.pmod/pgsql.pike:388: 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 && !conn.peek(0)) {
int tcurr=time();
int told=tcurr+timeout;
- while(!conn.peek(tcurr-told))
+ while(!conn.peek(told-tcurr))
if((tcurr=time())-told>=timeout) {
sendclose();cancelquery();
break;
}
}
}
- int msgtype=getbyte();
- int msglen=getint32();
+ int msgtype=GETBYTE();
+ int msglen=GETINT32();
enum errortype { noerror=0, protocolerror, protocolunsupported };
errortype errtype=noerror;
switch(msgtype) {
void getcols() {
- int bintext=getbyte();
+ int bintext=GETBYTE();
array a;
- int cols=getint16();
+ int cols=GETINT16();
msglen-=4+1+2+2*cols;
foreach(a=allocate(cols,([]));;mapping m)
- m->type=getint16();
+ m->type=GETINT16();
if(_portal) {
a=({(["type":bintext?BYTEAOID:TEXTOID,"name":"line"])});
_portal->_datarowdesc=a;
}
mstate=gotrowdescription;
};
array(string) getstrings() {
string s;
if(msglen<1)
errtype=protocolerror;
- s=getstring(msglen);
+ s=GETSTRING(msglen);
if(s[--msglen])
errtype=protocolerror;
if(!msglen)
return ({});
s=s[..msglen-1];msglen=0;
return s/"\0";
};
void getresponse() {
msglen-=4;
msgresponse=([]);
foreach(getstrings();;string f)
if(sizeof(f))
msgresponse[f[..0]]=f[1..];
PD("%O\n",msgresponse);
};
case 'R':PD("Authentication\n");
{ string sendpass;
int authtype;
msglen-=4+4;
- switch(authtype=getint32()) {
+ switch(authtype=GETINT32()) {
case 0:PD("Ok\n");
mstate=authenticated;
break;
case 2:PD("KerberosV5\n");
errtype=protocolunsupported;
break;
case 3:PD("ClearTextPassword\n");
sendpass=pass;
break;
case 4:PD("CryptPassword\n");
if(msglen<2)
errtype=protocolerror;
- sendpass=getstring(msglen);msglen=0;
+ sendpass=GETSTRING(msglen);msglen=0;
errtype=protocolunsupported;
break;
case 5:PD("MD5Password\n");
if(msglen<4)
errtype=protocolerror;
#if constant(Crypto.MD5.hash)
#define md5hex(x) String.string2hex(Crypto.MD5.hash(x))
sendpass=md5hex(pass+user);
- sendpass="md5"+md5hex(sendpass+getstring(msglen));
+ sendpass="md5"+md5hex(sendpass+GETSTRING(msglen));
#else
- getstring(msglen);
+ GETSTRING(msglen);
errtype=protocolunsupported;
#endif
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=getstring(msglen);msglen=0;
+ SSauthdata=GETSTRING(msglen);msglen=0;
break;
default:PD("Unknown Authentication Method %c\n",authtype);
errtype=protocolunsupported;
break;
}
switch(errtype) {
case noerror:
if(mstate==unauthenticated)
- sendcmd(({"p",plugint32(4+sizeof(sendpass)+1),
+ SENDCMD(({"p",plugint32(4+sizeof(sendpass)+1),
sendpass,"\0"}));
break;
default:
case protocolunsupported:
ERROR("Unsupported authenticationmethod %c\n",authtype);
break;
}
break;
}
case 'K':PD("BackendKeyData\n");
- msglen-=4+4;backendpid=getint32();cancelsecret=getstring(msglen);
+ msglen-=4+4;backendpid=GETINT32();cancelsecret=GETSTRING(msglen);
msglen=0;
break;
case 'S':PD("ParameterStatus\n");
msglen-=4;
{ array(string) ts=getstrings();
if(sizeof(ts)==2) {
runtimeparameter[ts[0]]=ts[1];
PD("%s=%s\n",ts[0],ts[1]);
}
else
errtype=protocolerror;
}
break;
case 'Z':PD("ReadyForQuery\n");
msglen-=4+1;
- backendstatus=getbyte();
+ backendstatus=GETBYTE();
mstate=readyforquery;
qstate=queryidle;
_closesent=0;
break;
case '1':PD("ParseComplete\n");
msglen-=4;
mstate=parsecomplete;
break;
case 't':
PD("ParameterDescription (for %s)\n",
_portal?_portal->_portalname:"DISCARDED");
{ array a;
- int cols=getint16();
+ int cols=GETINT16();
msglen-=4+2+4*cols;
foreach(a=allocate(cols);int i;)
- a[i]=getint32();
+ a[i]=GETINT32();
#ifdef DEBUGMORE
PD("%O\n",a);
#endif
if(_portal)
_portal->_datatypeoid=a;
mstate=gotparameterdescription;
break;
}
case 'T':
PD("RowDescription (for %s)\n",
_portal?_portal->_portalname:"DISCARDED");
msglen-=4+2;
{ array a;
- foreach(a=allocate(getint16());int i;) {
- string s="",ts;
- while(msglen--,(ts=getstring(1))[0])
- s+=ts;
+ foreach(a=allocate(GETINT16());int i;) {
+ string s;
+ msglen-=sizeof(s=GETSTRING())+1;
mapping(string:mixed) res=(["name":s]);
msglen-=4+2+4+2+4+2;
- res->tableoid=getint32()||UNDEFINED;
- res->tablecolattr=getint16()||UNDEFINED;
- res->type=getint32();
- { int len=getint16();
+ res->tableoid=GETINT32()||UNDEFINED;
+ res->tablecolattr=GETINT16()||UNDEFINED;
+ res->type=GETINT32();
+ { int len=GETINT16();
res->length=len>=0?len:"variable";
}
- res->atttypmod=getint32();res->formatcode=getint16();
+ res->atttypmod=GETINT32();res->formatcode=GETINT16();
a[i]=res;
}
#ifdef DEBUGMORE
PD("%O\n",a);
#endif
if(_portal)
_portal->_datarowdesc=a;
mstate=gotrowdescription;
break;
}
case 'n':PD("NoData\n");
msglen-=4;
_portal->_datarowdesc=({});
mstate=gotrowdescription;
break;
case '2':PD("BindComplete\n");
msglen-=4;
mstate=bindcomplete;
break;
case 'D':PD("DataRow\n");
- msglen-=4+2;
- { array a, datarowdesc;
+ msglen-=4;
if(_portal) {
-
+ array a, datarowdesc;
_portal->_bytesreceived+=msglen;
datarowdesc=_portal->_datarowdesc;
- }
- int cols=getint16();
- msglen-=4*cols;
- foreach(a=allocate(cols,"");int i;) {
- int collen=getint32();
+ #ifdef USEPGsql
+ a=conn.decodedatarow(msglen,datarowdesc);msglen=0;
+ #else
+ int cols=GETINT16();
+ a=allocate(cols,UNDEFINED);
+ msglen-=2+4*cols;
+ foreach(a;int i;) {
+ int collen=GETINT32();
if(collen>0) {
msglen-=collen;
mixed value;
- if(datarowdesc) {
+
switch(datarowdesc[i]->type) {
- default:value=getstring(collen);
+ default:value=GETSTRING(collen);
break;
case CHAROID:
- case BOOLOID:value=getbyte();
+ case BOOLOID:value=GETBYTE();
break;
case INT8OID:value=getint64();
break;
- case FLOAT4OID:value=(float)getstring(collen);
+ case FLOAT4OID:value=(float)GETSTRING(collen);
break;
- case INT2OID:value=getint16();
+ case INT2OID:value=GETINT16();
break;
case OIDOID:
- case INT4OID:value=getint32();
+ case INT4OID:value=GETINT32();
}
a[i]=value;
}
-
+ else if(!collen)
+ a[i]="";
}
- else if(collen)
- a[i]=UNDEFINED; // NULL
+ #endif
+ _portal->_datarows+=({a});
+ _portal->_inflight--;
}
- if(_portal)
- _portal->_datarows+=({a}),_portal->_inflight--;
+ else
+ GETSTRING(msglen),msglen=0;
mstate=dataready;
break;
- }
+
case 's':PD("PortalSuspended\n");
msglen-=4;
mstate=portalsuspended;
break;
case 'C':PD("CommandComplete\n");
{ msglen-=4;
if(msglen<1)
errtype=protocolerror;
- string s=getstring(msglen-1);
+ string s=GETSTRING(msglen-1);
if(_portal)
_portal->_statuscmdcomplete=s;
PD("%s\n",s);
- if(getbyte())
+ if(GETBYTE())
errtype=protocolerror;
msglen=0;
mstate=commandcomplete;
break;
}
case 'I':PD("EmptyQueryResponse\n");
msglen-=4;
mstate=commandcomplete;
break;
case '3':PD("CloseComplete\n");
msglen-=4;
_closesent=0;
break;
case 'd':PD("CopyData\n");
msglen-=4;
if(msglen<0)
errtype=protocolerror;
if(_portal) {
_portal->_bytesreceived+=msglen;
- _portal->_datarows+=({({getstring(msglen)})});
+ _portal->_datarows+=({({GETSTRING(msglen)})});
}
msglen=0;
mstate=dataready;
break;
case 'H':PD("CopyOutResponse\n");
getcols();
if(_portal)
_portal->_fetchlimit=0; // disables further Executes
break;
case 'G':PD("CopyInResponse\n");
pike.git/lib/modules/Sql.pmod/pgsql.pike:699:
ERROR(lastmessage);
}
break;
case 'N':PD("NoticeResponse\n");
getresponse();
lastmessage=sprintf("%s %s: %s",
msgresponse->S,msgresponse->C,msgresponse->M);
break;
case 'A':PD("NotificationResponse\n");
{ msglen-=4+4;
- int pid=getint32();
+ int pid=GETINT32();
string condition,extrainfo=UNDEFINED;
{ array(string) ts=getstrings();
switch(sizeof(ts)) {
case 0:errtype=protocolerror;
break;
default:errtype=protocolerror;
case 2:extrainfo=ts[1];
case 1:condition=ts[0];
}
}
PD("%d %s\n%s\n",pid,condition,extrainfo);
array cb;
if((cb=notifylist[condition]||notifylist[""])
&& (pid!=backendpid || sizeof(cb)>1 && cb[1]))
cb[0](pid,condition,extrainfo,@cb[2..]);
break;
}
default:PD("Unknown message received %c\n",msgtype);
- msglen-=4;PD("%O\n",getstring(msglen));msglen=0;
+ msglen-=4;PD("%O\n",GETSTRING(msglen));msglen=0;
errtype=protocolunsupported;
break;
}
if(msglen)
errtype=protocolerror;
switch(errtype) {
case protocolunsupported:
ERROR("Unsupported servermessage received %c\n",msgtype);
break;
case protocolerror:
pike.git/lib/modules/Sql.pmod/pgsql.pike:752:
private int read_cb(mixed foo, string d) {
conn.unread(d);
do decodemsg();
while(conn.peek(0)==1);
return 0;
}
final private void sendterminate() {
PD("Terminate\n");
- sendcmd(({"X",plugint32(4)}));
+ SENDCMD(({"X",plugint32(4)}));
conn.close();
}
void destroy() {
sendterminate();
}
private void reconnect(void|int force) {
if(conn) {
reconnected++;
pike.git/lib/modules/Sql.pmod/pgsql.pike:790:
plugbuf+=({"user\0",user,"\0"});
if(database)
plugbuf+=({"database\0",database,"\0"});
foreach(sessiondefaults;string name;string value)
plugbuf+=({name,"\0",value,"\0"});
plugbuf+=({"\0"});
int len=4;
foreach(plugbuf;;string s)
len+=sizeof(s);
plugbuf[0]=plugint32(len);
- sendcmd(plugbuf);
+ SENDCMD(plugbuf);
PD("%O\n",plugbuf);
decodemsg(readyforquery);
PD("%O\n",runtimeparameter);
}
//! @decl void reload()
//!
//! Resets the connection to the database. Can be used for
//! a variety of reasons, for example to detect the status of a connection.
void reload(void|int special) {
mixed err;
int didsync;
if(err = catch {
sendclose();
PD("Portalsinflight: %d\n",portalsinflight);
if(!portalsinflight) {
PD("Sync\n");
- sendcmd(({"S",plugint32(4)}),1);
+ SENDCMD(({"S",plugint32(4)}),1);
didsync=1;
- if(!special)
+ if(!special) {
decodemsg(readyforquery);
-
+ foreach(prepareds;;mapping tprepared) {
+ m_delete(tprepared,"datatypeoid");
+ m_delete(tprepared,"datarowdesc");
}
-
+ }
+ }
}) {
PD("%O\n",err);
reconnect(1);
}
else if(didsync && special==2)
decodemsg(readyforquery);
#ifndef UNBUFFEREDIO
conn.set_read_callback(read_cb);
#endif
}
pike.git/lib/modules/Sql.pmod/pgsql.pike:1110:
case CTIDOID:
case UUIDOID:
return 1; //binary
}
return 0; // text
}
final private void sendexecute(int fetchlimit) {
string portalname=_portal->_portalname;
PD("Execute portal %s fetchlimit %d\n",portalname,fetchlimit);
- sendcmd(({"E",plugint32(4+sizeof(portalname)+1+4),portalname,
+ SENDCMD(({"E",plugint32(4+sizeof(portalname)+1+4),portalname,
"\0",plugint32(fetchlimit)}),1);
_portal->_inflight+=fetchlimit;
}
final private void sendclose() {
string portalname;
portalsinflight--;
if(_portal && (portalname=_portal->_portalname)) {
_portal->_portalname = UNDEFINED;
_portal = UNDEFINED;
if(!sizeof(portalname))
unnamedportalinuse--;
#ifdef DEBUGMORE
PD("Closetrace %O\n",backtrace());
#endif
PD("Close portal %s\n",portalname);
- sendcmd(({"C",plugint32(4+1+sizeof(portalname)+1),
+ SENDCMD(({"C",plugint32(4+1+sizeof(portalname)+1),
"P",portalname,"\0"}));
_closesent=1;
}
}
final private string trbackendst(int c) {
switch(c) {
case 'I':return "idle";
case 'T':return "intransaction";
case 'E':return "infailedtransaction";
pike.git/lib/modules/Sql.pmod/pgsql.pike:1241:
string oldprep=tprepared->preparedname;
if(oldprep) {
PD("Close statement %s\n",oldprep);
plugbuf+=({"C",plugint32(4+1+sizeof(oldprep)+1),
"S",oldprep,"\0"});
}
m_delete(prepareds,ind);
}
}
if(sizeof(plugbuf))
- sendcmd(plugbuf); // close expireds
+ SENDCMD(plugbuf); // close expireds
PD("%O\n",plugbuf);
}
prepareds[q]=tprepared=([]);
}
tstart=gethrtime();
} // pgsql_result autoassigns to portal
pgsql_result(this,tprepared,q,_fetchlimit,portalbuffersize);
if(unnamedportalinuse)
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);
- sendcmd(({"P",plugint32(4+sizeof(preparedname)+1+sizeof(q)+1+2),
+ SENDCMD(({"P",plugint32(4+sizeof(preparedname)+1+sizeof(q)+1+2),
preparedname,"\0",q,"\0",plugint16(0)}));
PD("Query: %O\n",q);
} // sends Parameter- and RowDescription for 'S'
- PD("Describe statement %s\n",preparedname);
+
conn.set_read_callback(0);
- sendcmd(({"D",plugint32(4+1+sizeof(preparedname)+1),
+ if(!tprepared || !tprepared->datatypeoid) {
+ PD("Describe statement %s\n",preparedname);
+ SENDCMD(({"D",plugint32(4+1+sizeof(preparedname)+1),
"S",preparedname,"\0"}),1);
-
+ }
+ else {
+ _portal->_datatypeoid=tprepared->datatypeoid;
+ _portal->_datarowdesc=tprepared->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",
plugint16(sizeof(paramValues))});
-
+ if(!tprepared || !tprepared->datatypeoid) {
decodemsg(gotparameterdescription);
-
+ if(tprepared)
+ tprepared->datatypeoid=_portal->_datatypeoid;
+ }
array dtoid=_portal->_datatypeoid;
foreach(dtoid;;int textbin)
plugbuf+=({plugint16(oidformat(textbin))});
plugbuf+=({plugint16(sizeof(paramValues))});
foreach(paramValues;int i;mixed value) {
if(zero_type(value))
plugbuf+=({plugint32(-1)}); // NULL
else
switch(dtoid[i]) {
default:
pike.git/lib/modules/Sql.pmod/pgsql.pike:1325:
plugbuf+=({plugint32(8),plugint64((int)value)});
break;
case INT4OID:len+=4;
plugbuf+=({plugint32(4),plugint32((int)value)});
break;
case INT2OID:len+=2;
plugbuf+=({plugint32(2),plugint16((int)value)});
break;
}
}
+ if(!tprepared || !tprepared->datarowdesc) {
decodemsg(gotrowdescription);
-
+ if(tprepared)
+ tprepared->datarowdesc=_portal->_datarowdesc;
+ }
{ array a;int i;
len+=(i=sizeof(a=_portal->_datarowdesc))*2;
plugbuf+=({plugint16(i)});
foreach(a;;mapping col)
plugbuf+=({plugint16(oidformat(col->type))});
}
plugbuf[1]=plugint32(len);
PD("Bind portal %s statement %s\n",portalname,preparedname);
- sendcmd(plugbuf);
+ SENDCMD(plugbuf);
#ifdef DEBUGMORE
PD("%O\n",plugbuf);
#endif
}
_portal->_statuscmdcomplete=UNDEFINED;
sendexecute(_fetchlimit && FETCHLIMITLONGRUN);
if(tprepared) {
decodemsg(bindcomplete);
int tend=gethrtime();
if(tend==tstart)
pike.git/lib/modules/Sql.pmod/pgsql.pike:1490:
}
array(mapping(string:mixed)) fetch_fields() {
return _datarowdesc+({});
}
private void releasesession() {
if(pgsqlsession) {
if(copyinprogress) {
PD("CopyDone\n");
- pgsqlsession->sendmsg("c\0\0\0\4");
+ pgsqlsession.SENDCMD("c\0\0\0\4");
}
pgsqlsession->reload(2);
}
_qmtxkey=UNDEFINED;
pgsqlsession=UNDEFINED;
}
void destroy() {
catch { // inside destructors, exceptions don't work
releasesession();
pike.git/lib/modules/Sql.pmod/pgsql.pike:1548:
_qmtxkey=1;
#endif
pgsqlsession._portal=this;
PD("Stealing successful\n");
}
int|array(string|int) fetch_row(void|int|string buffer) {
if(copyinprogress) {
if(stringp(buffer)) {
PD("CopyData\n");
- pgsqlsession->sendmsg(({"d",plugint32(4+sizeof(buffer)),buffer}));
+ pgsqlsession.SENDCMD(({"d",plugint32(4+sizeof(buffer)),buffer}));
}
else
releasesession();
return UNDEFINED;
}
#ifndef NO_LOCKING
Thread.MutexKey fetchmtxkey = fetchmutex.lock();
#endif
if(!buffer && sizeof(_datarows))
return getdatarow();
pike.git/lib/modules/Sql.pmod/pgsql.pike:1570:
if(buffer!=2 && (err=delayederror)) {
delayederror=UNDEFINED;
throw(err);
}
err = catch {
if(_portalname) {
if(buffer!=2 && !_qmtxkey) {
steallock();
sendexecute(_fetchlimit);
}
- while(_closesent)
+ while(pgsqlsession->_closesent)
decodemsg(); // Flush previous portal sequence
for(;;) {
#ifdef DEBUGMORE
PD("buffer: %d nextportal: %d lock: %d\n",
buffer,pgsqlsession._nextportal,!!_qmtxkey);
#endif
switch(decodemsg()) {
case copyinresponse:
copyinprogress=1;
return UNDEFINED;
- case dataready: {
+ case dataready:
if(tprepared) {
tprepared->trun=gethrtime()-tprepared->trunstart;
m_delete(tprepared,"trunstart");
tprepared = UNDEFINED;
}
mstate=dataprocessed;
rowsreceived++;
switch(buffer) {
case 0:
case 1:
pike.git/lib/modules/Sql.pmod/pgsql.pike:1612:
_interruptable=1;
if(pgsqlsession._nextportal)
continue;
return UNDEFINED;
}
#if STREAMEXECUTES
if(_fetchlimit && _inflight<=_fetchlimit-1)
sendexecute(_fetchlimit); // Overlap Executes
#endif
return getdatarow();
- }
+
case commandcomplete:
releasesession();
switch(buffer) {
case 1:
case 2:
return UNDEFINED;
case 3:
if(sizeof(_datarows))
return getdatarow();
}