a2014e | 2008-07-14 | Stephen R. van den Berg | |
#pike __REAL_VERSION__
#ifdef DEBUG
|
e22cab | 2008-07-14 | Stephen R. van den Berg | | #define PD(X ...) werror(X)
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #define UNBUFFEREDIO 1 // Make all IO unbuffered
#else
#undef DEBUGMORE
#define PD(X ...)
#endif
|
e22cab | 2008-07-14 | Stephen R. van den Berg | |
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #define USEPGsql 1 // Doesn't use Stdio.FILE, but PG assist
#ifdef USEPGsql
#define UNBUFFEREDIO 1
#endif
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
#define FETCHLIMIT 1024 // Initial upper limit on the
#define FETCHLIMITLONGRUN 1 // for long running background queries
#define STREAMEXECUTES 1 // streams executes if defined
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #define MINPREPARELENGTH 16 // statements shorter than this will not
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
#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
|
e22cab | 2008-07-14 | Stephen R. van den Berg | | #define ERROR(X ...) predef::error(X)
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
pgsql_result _portal;
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 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};
private querystate qstate;
private mapping(string:mapping(string:mixed)) prepareds=([]);
private int pstmtcount;
private int pportalcount;
private int totalhits;
private int cachedepth=1024;
private int timeout=4096;
private int portalbuffersize=64*1024;
private int reconnected;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #ifndef USEPGsql
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | private int flushed;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #endif
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
private string host, database, user, pass;
private int port;
private mapping(string:string) sessiondefaults=([]);
private Thread.Mutex querymutex;
private Thread.Mutex stealmutex;
protected string _sprintf(int type, void|mapping flags) {
string res=UNDEFINED;
switch(type) {
case 'O':
res=sprintf(DRIVERNAME"://%s@%s:%d/%s pid:%d %s reconnected:%d\n"
"mstate: %O qstate: %O pstmtcount: %d pportalcount: %d\n"
"Last query: %O\n"
"Last message: %s\n"
"Last error: %O\n"
"portal %d %O\n%O\n",
user,host,port,database,backendpid,status_commit(),reconnected,
mstate,qstate,pstmtcount,pportalcount,
_portal&&_portal->query||"",
lastmessage||"",
msgresponse,
!!_portal,runtimeparameter,prepareds);
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
#define MACADDROID 829
#define INETOID 869
#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"
|
1fe399 | 2008-07-16 | Peter Bortas | |
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
protected void create(void|string _host, void|string _database,
void|string _user, void|string _pass) {
pass = _pass; _pass = "CENSORED";
user = _user; database = _database; host = _host || PGSQL_DEFAULT_HOST;
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();
}
string error(void|int clear) {
string s=lastmessage;
if(clear)
lastmessage=UNDEFINED;
return s;
}
string host_info() {
return sprintf("Via fd:%d over TCP/IP to %s:%d",conn->query_fd(),host,port);
}
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #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
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
final private void sendflush() {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(({}),1);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
inline final private int getbyte() {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!FLUSHED && !conn.peek(0))
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | sendflush();
#ifdef UNBUFFEREDIO
return conn.read(1)[0];
#else
return conn.getchar();
#endif
}
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | final private string getstring(void|int len) {
if(!zero_type(len)) {
string acc="",res;
do {
if(!FLUSHED && !conn.peek(0))
sendflush();
res=conn.read(len,!FLUSHED);
if(res) {
if(!sizeof(res))
return acc;
acc+=res;
}
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | while(sizeof(acc)<len&&res);
return sizeof(acc)?acc:res;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | array(int) acc=({});
int c;
while((c=GETBYTE())>0)
acc+=({c});
return `+("",@map(acc,String.int2char));
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
inline final private int getint16() {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | int s0=GETBYTE();
int r=(s0&0x7f)<<8|GETBYTE();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | return s0&0x80 ? r-(1<<15) : r ;
}
inline final private int getint32() {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | int r=GETINT16();
r=r<<8|GETBYTE();
return r<<8|GETBYTE();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
inline final private int getint64() {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | 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);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
#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);
}
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #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
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | final private object getsocket() {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #ifdef USEPGsql
object lcon = PGassist();
#else
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #ifdef UNBUFFEREDIO
object lcon = Stdio.File();
#else
object lcon = Stdio.FILE();
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #endif
flushed=-1;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #endif
return lcon.connect(host,port) && lcon;
}
void cancelquery() {
if(qstate==inquery) {
qstate=cancelpending;
object lcon;
PD("CancelRequest\n");
if(!(lcon=getsocket()))
ERROR("Cancel connect failed\n");
lcon.write(({plugint32(16),plugint32(PG_PROTOCOL(1234,4567)),
plugint32(backendpid),cancelsecret}));
lcon.close();
}
}
int setcachedepth(void|int newdepth) {
int olddepth=cachedepth;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!zero_type(newdepth) && newdepth>=0)
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | cachedepth=newdepth;
return olddepth;
}
int settimeout(void|int newtimeout) {
int oldtimeout=timeout;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!zero_type(newtimeout) && newtimeout>0)
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | timeout=newtimeout;
return oldtimeout;
}
int setportalbuffersize(void|int newportalbuffersize) {
int oldportalbuffersize=portalbuffersize;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!zero_type(newportalbuffersize) && newportalbuffersize>0)
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | portalbuffersize=newportalbuffersize;
return oldportalbuffersize;
}
int setfetchlimit(void|int newfetchlimit) {
int oldfetchlimit=_fetchlimit;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!zero_type(newfetchlimit) && newfetchlimit>=0)
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | _fetchlimit=newfetchlimit;
return oldfetchlimit;
}
final private string glob2reg(string glob) {
if (!glob||!sizeof(glob))
return "%";
return replace(glob,({"*","?","\\","%","_"}),({"%","_","\\\\","\\%","\\_"}));
}
final private string addnlifpresent(void|string msg) {
return msg?msg+"\n":"";
}
final private string pinpointerror(void|string query,void|string offset) {
if(!query)
return "";
int k=(int)offset;
if(k<=0)
return MARKSTART+query+MARKEND;
return MARKSTART+(k>1?query[..k-2]:"")+MARKERROR+query[k-1..]+MARKEND;
}
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | final int _decodemsg(void|state waitforstate) {
|
a2014e | 2008-07-14 | Stephen 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
while(mstate!=waitforstate) {
if(mstate!=unauthenticated) {
if(qstate==cancelpending)
qstate=canceled,sendclose();
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(FLUSHED && qstate==inquery && !conn.peek(0)) {
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | int tcurr=time();
int told=tcurr+timeout;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | while(!conn.peek(told-tcurr))
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if((tcurr=time())-told>=timeout) {
sendclose();cancelquery();
break;
}
}
}
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | int msgtype=GETBYTE();
int msglen=GETINT32();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | enum errortype { noerror=0, protocolerror, protocolunsupported };
errortype errtype=noerror;
switch(msgtype) {
void getcols() {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | int bintext=GETBYTE();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | array a;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | int cols=GETINT16();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | msglen-=4+1+2+2*cols;
foreach(a=allocate(cols,([]));;mapping m)
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | m->type=GETINT16();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(_portal) {
a=({(["type":bintext?BYTEAOID:TEXTOID,"name":"line"])});
_portal->_datarowdesc=a;
}
mstate=gotrowdescription;
};
array(string) getstrings() {
string s;
if(msglen<1)
errtype=protocolerror;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | s=GETSTRING(msglen);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | switch(authtype=GETINT32()) {
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | sendpass=GETSTRING(msglen);msglen=0;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | sendpass="md5"+md5hex(sendpass+GETSTRING(msglen));
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #else
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | GETSTRING(msglen);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SSauthdata=GETSTRING(msglen);msglen=0;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | break;
default:PD("Unknown Authentication Method %c\n",authtype);
errtype=protocolunsupported;
break;
}
switch(errtype) {
case noerror:
if(mstate==unauthenticated)
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(({"p",plugint32(4+sizeof(sendpass)+1),
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | sendpass,"\0"}));
break;
default:
case protocolunsupported:
ERROR("Unsupported authenticationmethod %c\n",authtype);
break;
}
break;
}
case 'K':PD("BackendKeyData\n");
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | msglen-=4+4;backendpid=GETINT32();cancelsecret=GETSTRING(msglen);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | backendstatus=GETBYTE();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | int cols=GETINT16();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | msglen-=4+2+4*cols;
foreach(a=allocate(cols);int i;)
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | a[i]=GETINT32();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | foreach(a=allocate(GETINT16());int i;) {
string s;
msglen-=sizeof(s=GETSTRING())+1;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | mapping(string:mixed) res=(["name":s]);
msglen-=4+2+4+2+4+2;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | res->tableoid=GETINT32()||UNDEFINED;
res->tablecolattr=GETINT16()||UNDEFINED;
res->type=GETINT32();
{ int len=GETINT16();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | res->length=len>=0?len:"variable";
}
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | res->atttypmod=GETINT32();res->formatcode=GETINT16();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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");
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | msglen-=4;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(_portal) {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | #ifdef USEPGsql
conn.decodedatarow(msglen,_portal);msglen=0;
#else
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | array a, datarowdesc;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | _portal->_bytesreceived+=msglen;
datarowdesc=_portal->_datarowdesc;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | 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;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | switch(datarowdesc[i]->type) {
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | default:value=GETSTRING(collen);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | break;
case CHAROID:
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | case BOOLOID:value=GETBYTE();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | break;
case INT8OID:value=getint64();
break;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | case FLOAT4OID:value=(float)GETSTRING(collen);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | break;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | case INT2OID:value=GETINT16();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | break;
case OIDOID:
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | case INT4OID:value=GETINT32();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
a[i]=value;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | }
else if(!collen)
a[i]="";
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | a=({a});
_portal->_datarows+=a;
_portal->_inflight-=sizeof(a);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | #endif
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | else
GETSTRING(msglen),msglen=0;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | string s=GETSTRING(msglen-1);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(_portal)
_portal->_statuscmdcomplete=s;
PD("%s\n",s);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(GETBYTE())
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | _portal->_datarows+=({({GETSTRING(msglen)})});
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
msglen=0;
mstate=dataready;
break;
case 'H':PD("CopyOutResponse\n");
getcols();
if(_portal)
_portal->_fetchlimit=0;
break;
case 'G':PD("CopyInResponse\n");
getcols();
mstate=copyinresponse;
break;
case 'c':PD("CopyDone\n");
msglen-=4;
break;
case 'E':PD("ErrorResponse\n");
getresponse();
switch(msgresponse->C) {
case "P0001":
lastmessage=sprintf("%s: %s",msgresponse->S,msgresponse->M);
ERROR(lastmessage
+"\n"+pinpointerror(_portal->query,msgresponse->P));
break;
default:
lastmessage=sprintf("%s %s:%s %s\n (%s:%s:%s)\n%s%s%s%s\n%s",
msgresponse->S,msgresponse->C,msgresponse->P||"",msgresponse->M,
msgresponse->F||"",msgresponse->R||"",msgresponse->L||"",
addnlifpresent(msgresponse->D),addnlifpresent(msgresponse->H),
pinpointerror(_portal&&_portal->query,msgresponse->P),
pinpointerror(msgresponse->q,msgresponse->p),
addnlifpresent(msgresponse->W));
switch(msgresponse->S) {
case "PANIC":werror(lastmessage);
}
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;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | int pid=GETINT32();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | msglen-=4;PD("%O\n",GETSTRING(msglen));msglen=0;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | errtype=protocolunsupported;
break;
}
if(msglen)
errtype=protocolerror;
switch(errtype) {
case protocolunsupported:
ERROR("Unsupported servermessage received %c\n",msgtype);
break;
case protocolerror:
reconnect(1);
ERROR("Protocol error with databasel %s@%s:%d/%s\n",
user,host,port,database);
break;
case noerror:
break;
}
if(zero_type(waitforstate))
break;
}
PD("Found state %O\n",mstate);
return mstate;
}
|
0e0cfa | 2008-07-25 | Henrik Grubbström (Grubba) | | #ifndef UNBUFFEREDIO
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | private int read_cb(mixed foo, string d) {
conn.unread(d);
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | do _decodemsg();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | while(conn.peek(0)==1);
return 0;
}
|
0e0cfa | 2008-07-25 | Henrik Grubbström (Grubba) | | #endif
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
final private void sendterminate() {
PD("Terminate\n");
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(({"X",plugint32(4)}));
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | conn.close();
}
void destroy() {
sendterminate();
}
private void reconnect(void|int force) {
if(conn) {
reconnected++;
#ifdef DEBUG
ERROR("While debugging, reconnects are forbidden\n");
exit(1);
#endif
if(!force)
sendterminate();
foreach(prepareds;;mapping tprepared)
m_delete(tprepared,"preparedname");
}
if(!(conn=getsocket()))
ERROR("Couldn't connect to database on %s:%d\n",host,port);
_closesent=0;
mstate=unauthenticated;
qstate=queryidle;
runtimeparameter=([]);
array(string) plugbuf=({"",plugint32(PG_PROTOCOL(3,0))});
if(user)
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);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(plugbuf);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | PD("%O\n",plugbuf);
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _decodemsg(readyforquery);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | PD("%O\n",runtimeparameter);
}
void reload(void|int special) {
mixed err;
int didsync;
if(err = catch {
sendclose();
PD("Portalsinflight: %d\n",portalsinflight);
if(!portalsinflight) {
PD("Sync\n");
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(({"S",plugint32(4)}),1);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | didsync=1;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!special) {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _decodemsg(readyforquery);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | foreach(prepareds;;mapping tprepared) {
m_delete(tprepared,"datatypeoid");
m_delete(tprepared,"datarowdesc");
}
}
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
}) {
PD("%O\n",err);
reconnect(1);
}
else if(didsync && special==2)
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _decodemsg(readyforquery);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #ifndef UNBUFFEREDIO
conn.set_read_callback(read_cb);
#endif
}
void select_db(string dbname) {
database=dbname;
reconnect();
}
|
9b77ae | 2008-07-16 | Peter Bortas | |
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
void set_notify_callback(string condition,
void|function(int,string,string,mixed ...:void) notify_cb,void|int selfnotify,
mixed ... args) {
if(!notify_cb)
m_delete(notifylist,condition);
else {
array old=notifylist[condition];
if(!old)
old=({notify_cb});
if(selfnotify||args)
old+=({selfnotify});
if(args)
old+=args;
notifylist[condition]=old;
}
}
string quote(string s) {
string r=runtimeparameter->standard_conforming_strings;
if(r && r=="on")
return replace(s, "'", "''");
return replace(s, ({ "'", "\\" }), ({ "''", "\\\\" }) );
}
void create_db(string db) {
big_query("CREATE DATABASE :db",([":db":db]));
}
void drop_db(string db) {
big_query("DROP DATABASE :db",([":db":db]));
}
string server_info () {
return DRIVERNAME"/"+(runtimeparameter->server_version||"unknown");
}
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;
}
array(string) list_tables (void|string glob) {
array row,ret=({});
object res=big_query(
"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;
}
array(mapping(string:mixed)) list_fields(void|string table, void|string wild) {
array row, ret=({});
string schema=UNDEFINED;
sscanf(table||"*", "%s.%s", schema, table);
object res = big_query(
"SELECT a.attname, a.atttypid, t.typname, a.attlen, "
" c.relhasindex, c.relhaspkey, c.reltuples, c.relpages, "
" 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' "
" WHEN 't' THEN 'toastable' "
" WHEN 'c' THEN 'composite' "
" ELSE c.relkind::TEXT END AS relkind, "
" r.rolname "
"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 "
"WHERE c.relname ILIKE :table AND "
" (n.nspname ILIKE :schema OR "
" :schema IS NULL "
" AND n.nspname<>'pg_catalog' AND n.nspname !~ '^pg_toast') "
" AND a.attname ILIKE :wild "
" AND (a.attnum>0 OR '*'=:realwild) "
"ORDER BY n.nspname,c.relname,a.attnum,a.attname",
([":schema":glob2reg(schema),":table":glob2reg(table),
":wild":glob2reg(wild),":realwild":wild]));
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",
"relpages":"pagecount",
]);
foreach(colnames;int i;mapping m) {
string nf,field=m->name;
if(nf=renames[field])
field=nf;
colnames[i]=field;
}
}
#define delifzero(m,field) if(!(m)[field]) m_delete(m,field)
while(row=res->fetch_row()) {
mapping m=mkmapping(colnames,row);
delifzero(m,"is_shared");
delifzero(m,"has_index");
delifzero(m,"has_primarykey");
delifzero(m,"default");
ret+=({m});
}
return ret;
}
private int oidformat(int oid) {
switch(oid) {
case BOOLOID:
case BYTEAOID:
case CHAROID:
case INT8OID:
case INT2OID:
case INT4OID:
case TEXTOID:
case OIDOID:
case XMLOID:
case MACADDROID:
case INETOID:
case BPCHAROID:
case VARCHAROID:
case CTIDOID:
case UUIDOID:
return 1;
}
return 0;
}
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | final void _sendexecute(int fetchlimit) {
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | string portalname=_portal->_portalname;
PD("Execute portal %s fetchlimit %d\n",portalname,fetchlimit);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(({"E",plugint32(4+sizeof(portalname)+1+4),portalname,
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | "\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);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(({"C",plugint32(4+1+sizeof(portalname)+1),
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | "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";
}
return "unknown";
}
final string status_commit() {
return trbackendst(backendstatus);
}
object big_query(string q,void|mapping(string|int:mixed) bindings) {
string preparedname="";
string portalname="";
if(stringp(q) && String.width(q)>8)
q=string_to_utf8(q);
array(string|int) paramValues;
if(bindings) {
int pi=0,rep=0;
paramValues=allocate(sizeof(bindings));
array(string) from=allocate(sizeof(bindings));
array(string) to=allocate(sizeof(bindings));
foreach(bindings; mixed name; mixed value) {
if(stringp(name)) {
if(name[0]!=':')
name=":"+name;
if(name[1]=='_') {
continue;
}
}
from[rep]=name;
string rval;
if(multisetp(value)) {
rval=sizeof(value) ? indices(value)[0] : "";
}
else {
if(zero_type(value))
paramValues[pi++]=UNDEFINED;
else {
if(stringp(value) && String.width(value)>8)
value=string_to_utf8(value);
paramValues[pi++]=value;
}
rval="$"+(string)pi;
}
to[rep++]=rval;
}
if(rep--)
q=replace(q,from[..rep],to[..rep]);
paramValues= pi ? paramValues[..pi-1] : ({});
}
else
paramValues = ({});
int tstart;
mapping(string:mixed) tprepared;
if(sizeof(q)>=MINPREPARELENGTH) {
if(tprepared=prepareds[q]) {
if(tprepared->preparedname)
preparedname=tprepared->preparedname;
else if((tstart=tprepared->trun)
&& tprepared->tparse*FACTORPLAN>=tstart)
preparedname=PREPSTMTPREFIX+(string)pstmtcount++;
}
else {
if(totalhits>=cachedepth) {
array(string) plugbuf=({});
foreach(prepareds;string ind;tprepared) {
int oldhits=tprepared->hits;
totalhits-=oldhits-(tprepared->hits=oldhits>>1);
if(oldhits<=1) {
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))
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(plugbuf);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | PD("%O\n",plugbuf);
}
prepareds[q]=tprepared=([]);
}
tstart=gethrtime();
}
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);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(({"P",plugint32(4+sizeof(preparedname)+1+sizeof(q)+1+2),
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | preparedname,"\0",q,"\0",plugint16(0)}));
PD("Query: %O\n",q);
}
conn.set_read_callback(0);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | 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;
}
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | { 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))});
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!tprepared || !tprepared->datatypeoid) {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _decodemsg(gotparameterdescription);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(tprepared)
tprepared->datatypeoid=_portal->_datatypeoid;
}
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | 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)});
else
switch(dtoid[i]) {
default:
{ int k;
len+=k=sizeof(value=(string)value);
plugbuf+=({plugint32(k),value});
break;
}
case BOOLOID:plugbuf+=({plugint32(1)});len++;
switch(stringp(value)?value[0]:value) {
case 'o':case 'O':
plugbyte(stringp(value)&&sizeof(value)>1
&&(value[1]=='n'||value[1]=='N'));
break;
case 0:case 'f':case 'F':case 'n':case 'N':
plugbuf+=({plugbyte(0)});
break;
default:
plugbuf+=({plugbyte(1)});
break;
}
break;
case CHAROID:plugbuf+=({plugint32(1)});len++;
if(intp(value))
plugbuf+=({plugbyte(value)});
else {
value=(string)value;
if(sizeof(value)!=1)
ERROR("\"char\" types must be 1 byte wide, got %d\n",
sizeof(value));
plugbuf+=({value});
}
break;
case INT8OID:len+=8;
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;
}
}
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(!tprepared || !tprepared->datarowdesc) {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _decodemsg(gotrowdescription);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | if(tprepared)
tprepared->datarowdesc=_portal->_datarowdesc;
}
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | { 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);
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | SENDCMD(plugbuf);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #ifdef DEBUGMORE
PD("%O\n",plugbuf);
#endif
}
_portal->_statuscmdcomplete=UNDEFINED;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _sendexecute(_fetchlimit && FETCHLIMITLONGRUN);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(tprepared) {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _decodemsg(bindcomplete);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | int tend=gethrtime();
if(tend==tstart)
m_delete(prepareds,q);
else {
tprepared->hit++;
totalhits++;
if(!tprepared->preparedname) {
if(sizeof(preparedname))
tprepared->preparedname=preparedname;
tstart=tend-tstart;
if(tprepared->tparse>tstart)
tprepared->tparse=tstart;
else
tstart=tprepared->tparse;
}
tprepared->trunstart=tend;
}
}
}) {
PD("%O\n",err);
reload(1);
backendstatus=UNDEFINED;
throw(err);
}
{ pgsql_result tportal=_portal;
tportal->fetch_row(1);
return tportal;
}
}
object streaming_query(string q,void|mapping(string|int:mixed) bindings) {
return big_query(q,bindings);
}
class pgsql_result {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | object _pgsqlsess;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | private int numrows;
private int eoffound;
private mixed delayederror;
private int copyinprogress;
int _fetchlimit;
private mapping tprepared;
|
e22cab | 2008-07-14 | Stephen R. van den Berg | | #ifdef NO_LOCKING
int _qmtxkey;
#else
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | Thread.MutexKey _qmtxkey;
|
e22cab | 2008-07-14 | Stephen R. van den Berg | | #endif
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
string query;
string _portalname;
int _bytesreceived;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | int _rowsreceived;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | int _interruptable;
int _inflight;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | int _portalbuffersize;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | string _statuscmdcomplete;
array(array(mixed)) _datarows;
array(mapping(string:mixed)) _datarowdesc;
array(int) _datatypeoid;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | #ifdef USEPGsql
int _buffer;
#endif
|
a2014e | 2008-07-14 | Stephen R. van den Berg | |
private object fetchmutex;;
protected string _sprintf(int type, void|mapping flags) {
string res=UNDEFINED;
switch(type) {
case 'O':
res=sprintf(DRIVERNAME"_result numrows: %d eof: %d querylock: %d"
" inflight: %d portalname: %O\n"
"query: %O\n"
"laststatus: %s\n"
"%O\n"
"%O\n",
numrows,eoffound,!!_qmtxkey,_inflight,_portalname,
query,
_statuscmdcomplete||"",
_datarowdesc,
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | break;
}
return res;
}
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | void create(object pgsqlsess,mapping(string:mixed) _tprepared,
string _query,int fetchlimit,int portalbuffersize) {
_pgsqlsess = pgsqlsess;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | tprepared = _tprepared; query = _query;
_datarows = ({ }); numrows = UNDEFINED;
fetchmutex = Thread.Mutex();
_fetchlimit=fetchlimit;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _portalbuffersize=portalbuffersize;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | steallock();
}
string status_command_complete() {
return _statuscmdcomplete;
}
int affected_rows() {
int rows;
if(_statuscmdcomplete)
sscanf(_statuscmdcomplete,"%*s %d",rows);
return rows;
}
int num_fields() {
return sizeof(_portal->datarowdesc);
}
int num_rows() {
int numrows;
sscanf(_statuscmdcomplete,"%*s %d",numrows);
return numrows;
}
int eof() {
return eoffound;
}
array(mapping(string:mixed)) fetch_fields() {
return _datarowdesc+({});
}
private void releasesession() {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | if(_pgsqlsess) {
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(copyinprogress) {
PD("CopyDone\n");
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess.SENDCMD("c\0\0\0\4");
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess.reload(2);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
_qmtxkey=UNDEFINED;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess=UNDEFINED;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
void destroy() {
catch {
releasesession();
};
}
inline private array(mixed) getdatarow() {
array(mixed) datarow=_datarows[0];
_datarows=_datarows[1..];
return datarow;
}
private void steallock() {
|
e22cab | 2008-07-14 | Stephen R. van den Berg | | #ifndef NO_LOCKING
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | PD("Going to steal oldportal %d\n",!!_pgsqlsess._portal);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | Thread.MutexKey stealmtxkey = stealmutex.lock();
do
if(_qmtxkey = querymutex.current_locking_key()) {
pgsql_result portalb;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | if(portalb=_pgsqlsess._portal) {
_pgsqlsess._nextportal++;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(portalb->_interruptable)
portalb->fetch_row(2);
else {
PD("Waiting for the querymutex\n");
if((_qmtxkey=querymutex.lock(2))) {
if(copyinprogress)
ERROR("COPY needs to be finished first\n");
ERROR("Driver bug, please report, "
"conflict while interleaving SQL-operations\n");
}
PD("Got the querymutex\n");
}
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess._nextportal--;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
break;
}
while(!(_qmtxkey=querymutex.trylock()));
|
e22cab | 2008-07-14 | Stephen R. van den Berg | | #else
PD("Skipping lock\n");
_qmtxkey=1;
#endif
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess._portal=this;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | PD("Stealing successful\n");
}
int|array(string|int) fetch_row(void|int|string buffer) {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | #ifndef NO_LOCKING
Thread.MutexKey fetchmtxkey = fetchmutex.lock();
#endif
if(!buffer && sizeof(_datarows))
return getdatarow();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(copyinprogress) {
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | fetchmtxkey = UNDEFINED;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(stringp(buffer)) {
PD("CopyData\n");
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess.SENDCMD(({"d",plugint32(4+sizeof(buffer)),buffer}));
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
else
releasesession();
return UNDEFINED;
}
mixed err;
if(buffer!=2 && (err=delayederror)) {
delayederror=UNDEFINED;
throw(err);
}
err = catch {
if(_portalname) {
if(buffer!=2 && !_qmtxkey) {
steallock();
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess._sendexecute(_fetchlimit);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | while(_pgsqlsess._closesent)
_pgsqlsess._decodemsg();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | for(;;) {
#ifdef DEBUGMORE
PD("buffer: %d nextportal: %d lock: %d\n",
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | buffer,_pgsqlsess._nextportal,!!_qmtxkey);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #endif
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | #ifdef USEPGsql
_buffer=buffer;
#endif
switch(_pgsqlsess._decodemsg()) {
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | case copyinresponse:
copyinprogress=1;
return UNDEFINED;
|
488ce7 | 2008-07-24 | Stephen R. van den Berg | | case dataready:
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(tprepared) {
tprepared->trun=gethrtime()-tprepared->trunstart;
m_delete(tprepared,"trunstart");
tprepared = UNDEFINED;
}
mstate=dataprocessed;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _rowsreceived++;
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | switch(buffer) {
case 0:
case 1:
if(_fetchlimit)
_fetchlimit=
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | min(_portalbuffersize/2*_rowsreceived/_bytesreceived || 1,
_pgsqlsess._fetchlimit);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | }
switch(buffer) {
case 2:
case 3:
continue;
case 1:
_interruptable=1;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | if(_pgsqlsess._nextportal)
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | continue;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | #if STREAMEXECUTES
if(_fetchlimit && _inflight<=_fetchlimit-1)
_pgsqlsess._sendexecute(_fetchlimit);
#endif
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | return UNDEFINED;
}
#if STREAMEXECUTES
if(_fetchlimit && _inflight<=_fetchlimit-1)
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess._sendexecute(_fetchlimit);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | #endif
return getdatarow();
case commandcomplete:
releasesession();
switch(buffer) {
case 1:
case 2:
return UNDEFINED;
case 3:
if(sizeof(_datarows))
return getdatarow();
}
break;
case portalsuspended:
if(_inflight)
continue;
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | if(_pgsqlsess._nextportal) {
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | switch(buffer) {
case 1:
case 2:
_qmtxkey = UNDEFINED;
return UNDEFINED;
case 3:
_qmtxkey = UNDEFINED;
return getdatarow();
}
_fetchlimit=FETCHLIMITLONGRUN;
if(sizeof(_datarows)) {
_qmtxkey = UNDEFINED;
return getdatarow();
}
buffer=3;
}
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess._sendexecute(_fetchlimit);
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | default:
continue;
}
break;
}
}
eoffound=1;
return UNDEFINED;
};
PD("Exception %O\n",err);
|
49a328 | 2008-07-25 | Stephen R. van den Berg | | _pgsqlsess.reload();
|
a2014e | 2008-07-14 | Stephen R. van den Berg | | if(buffer!=2)
throw(err);
if(!delayederror)
delayederror=err;
return UNDEFINED;
}
};
|