ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
#pike __REAL_VERSION__
#include "pgsql.h"
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | |
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected Thread.Mutex backendmux;
final Pike.Backend local_backend;
protected int clientsregistered;
protected void run_local_backend() {
Thread.MutexKey lock;
int looponce;
do {
looponce=0;
if(lock=backendmux->trylock()) {
PD("Starting local backend\n");
while(clientsregistered)
local_backend(4096.0);
PD("Terminating local backend\n");
lock=0;
looponce=clientsregistered;
}
} while(looponce);
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected void create() {
backendmux = Thread.Mutex();
local_backend = Pike.SmallBackend();
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void register_backend() {
if(!clientsregistered++)
Thread.Thread(run_local_backend);
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void unregister_backend() {
--clientsregistered;
}
|
4741cd | 2008-07-31 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void throwdelayederror(object parent) {
if(mixed err=parent._delayederror) {
parent._delayederror=UNDEFINED;
if(stringp(err))
err=({err,backtrace()[..<2]});
throw(err);
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | }
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected sctype mergemode(PGassist realbuffer,sctype mode) {
switch(realbuffer->stashflushmode) {
case sendout:
if(mode!=flushsend) {
mode=sendout;
break;
}
case flushsend:
mode=flushsend;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | return realbuffer->stashflushmode=mode;
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | |
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | class PGplugbuffer {
inherit Stdio.Buffer;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected PGassist realbuffer;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void create(PGassist _realbuffer) {
realbuffer=_realbuffer;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
d43282 | 2008-07-31 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final PGplugbuffer start(void|int waitforreal) {
realbuffer->stashcount++;
#ifdef PG_DEBUG
if(waitforreal)
error("pgsql.PGplugbuffer not allowed here\n");
|
d43282 | 2008-07-31 | Stephen R. van den Berg | | #endif
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | return this;
}
final
void sendcmd(void|sctype mode,void|object portal) {
Thread.MutexKey lock=realbuffer->stashupdate->lock();
if(portal)
realbuffer->stashqueue->write(portal);
realbuffer->stash->add(this);
mode=mergemode(realbuffer,mode);
if(!--realbuffer->stashcount)
realbuffer->stashavail.signal();
lock=0;
this->clear();
if(lock=realbuffer->nostash->trylock(1)) {
realbuffer->started=lock; lock=0;
realbuffer->sendcmd(sendout);
}
|
d43282 | 2008-07-31 | Stephen R. van den Berg | | }
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | }
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | class PGassist {
inherit Stdio.Buffer:i;
inherit Stdio.Buffer:o;
protected Thread.Condition condition;
protected Thread.Mutex mux;
protected Thread.Queue qportals;
final Stdio.File socket;
protected int towrite;
final function(:void) gottimeout;
final int timeout;
Thread.Mutex nostash;
Thread.MutexKey started;
Thread.Mutex stashupdate;
Thread.Queue stashqueue;
Thread.Condition stashavail;
Stdio.Buffer stash;
int stashflushmode;
int stashcount;
#ifdef PG_DEBUG
int queueoutidx;
int queueinidx;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | #endif
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final PGassist|PGplugbuffer start(void|int waitforreal) {
Thread.MutexKey lock;
if(lock=(waitforreal?nostash->lock:nostash->trylock)(1)) {
started=lock;
lock=stashupdate->lock();
if(stashcount) {
stashavail.wait(lock);
add(stash); stash->clear();
foreach(stashqueue->try_read_array();;pgsql_result qp) {
qportals->write(qp);
PD(">%O %d Queue portal %d bytes\n",qp._portalname,++queueoutidx,
sizeof(this));
}
}
lock=0;
return this;
}
stashcount++;
return PGplugbuffer(this);
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected final bool range_error(int howmuch) {
if(!howmuch)
return false;
#ifdef PG_DEBUG
if(howmuch<0)
error("Out of range %d\n",howmuch);
#endif
if(condition) {
array cid=local_backend->call_out(gottimeout,timeout);
Thread.MutexKey lock=mux->lock();
condition.wait(lock);
lock=0;
local_backend->remove_call_out(cid);
} else
throw(MAGICTERMINATE);
return true;
}
protected int read_cb(mixed id,mixed b) {
Thread.MutexKey lock=mux->lock();
if(condition)
condition.signal();
lock=0;
return 0;
}
protected int write_cb() {
towrite-=output_to(socket,towrite);
if(!condition && !sizeof(this))
socket->close();
return 0;
}
inline final int consume(int w) { return i::consume(w); }
inline final int unread(int w) { return i::unread(w); }
inline final string read(int w) { return i::read(w); }
inline final object read_buffer(int w) { return i::read_buffer(w); }
inline final int read_sint(int w) { return i::read_sint(w); }
inline final int read_int8() { return i::read_int8(); }
inline final int read_int16() { return i::read_int16(); }
inline final int read_int32() { return i::read_int32(); }
inline final string read_cstring() { return i::read_cstring(); }
final
void sendcmd(void|sctype mode,void|pgsql_result portal) {
if(portal) {
qportals->write(portal);
PD(">%O %d Queue portal %d bytes\n",portal._portalname,++queueoutidx,
sizeof(this));
}
if(started) {
Thread.MutexKey lock=stashupdate->lock();
if(sizeof(stash)) {
add(stash); stash->clear();
foreach(stashqueue->try_read_array();;pgsql_result qp) {
qportals->write(qp);
PD(">%O %d Queue portal %d bytes\n",qp._portalname,++queueoutidx,
sizeof(this));
}
}
mode=mergemode(this,mode);
stashflushmode=keep;
lock=0;
}
switch(mode) {
case flushsend:
add(PGFLUSH);
PD("Flush\n");
case sendout:
if(towrite+=sizeof(this)) {
PD(">Sendcmd %O\n",((string)this)[..towrite-1]);
towrite-=output_to(socket,towrite);
}
}
started=0;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void sendterminate() {
destruct(condition);
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final int close() {
return socket->close();
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void destroy() {
catch(close());
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void connectloop(object pgsqlsess,int nossl) {
mixed err=catch {
for(;;clear()) {
socket->connect(pgsqlsess._host,pgsqlsess._port);
|
fc7f09 | 2014-06-01 | Martin Nilsson | | #if constant(SSL.File)
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | if(!nossl && !pgsqlsess->nossl
&& (pgsqlsess.options.use_ssl || pgsqlsess.options.force_ssl)) {
PD("SSLRequest\n");
start()->add_int32(8)->add_int32(PG_PROTOCOL(1234,5679))
->sendcmd(sendout);
switch(read_int8()) {
case 'S':
object fcon=SSL.File(socket,SSL.Context());
if(fcon->connect()) {
socket=fcon;
break;
}
default:socket->close();
pgsqlsess.nossl=1;
continue;
case 'N':
if(pgsqlsess.options.force_ssl)
error("Encryption not supported on connection to %s:%d\n",
pgsqlsess.host,pgsqlsess.port);
}
}
#else
if(pgsqlsess.options.force_ssl)
error("Encryption library missing,"
" cannot establish connection to %s:%d\n",
pgsqlsess.host,pgsqlsess.port);
#endif
break;
}
socket->set_backend(local_backend);
socket->set_buffer_mode(i::this,0);
socket->set_nonblocking(read_cb,write_cb,0);
Thread.Thread(pgsqlsess->_processloop,this);
return;
};
pgsqlsess->_connectfail(err);
}
void create(object pgsqlsess,Thread.Queue _qportals,int nossl) {
i::create(); o::create();
qportals = _qportals;
condition=Thread.Condition();
mux=Thread.Mutex();
gottimeout=sendcmd;
timeout=128;
socket=Stdio.File();
nostash=Thread.Mutex();
stashupdate=Thread.Mutex();
stashqueue=Thread.Queue();
stashavail=Thread.Condition();
stash=Stdio.Buffer();
Thread.Thread(connectloop,pgsqlsess,nossl);
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
}
|
f4c9d6 | 2009-02-15 | Stephen R. van den Berg | |
|
041296 | 2009-01-19 | Stephen R. van den Berg | |
|
f4c9d6 | 2009-02-15 | Stephen R. van den Berg | |
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | class pgsql_result {
|
11b13b | 2014-08-16 | Martin Nilsson | | object _pgsqlsess;
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected int numrows;
protected int eoffound;
protected PGassist c;
mixed _delayederror;
portalstate _state;
|
11b13b | 2014-08-16 | Martin Nilsson | | int _fetchlimit;
int _alltext;
int _forcetext;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | | string _portalname;
int _bytesreceived;
int _rowsreceived;
int _inflight;
int _portalbuffersize;
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | Thread.MutexKey _unnamedportalkey,_unnamedstatementkey;
protected Thread.Mutex closemux;
|
11b13b | 2014-08-16 | Martin Nilsson | | array _params;
string _statuscmdcomplete;
string _query;
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | Thread.Queue _datarows;
|
11b13b | 2014-08-16 | Martin Nilsson | | array(mapping(string:mixed)) _datarowdesc=({});
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | int _oldpbpos;
object _plugbuffer;
string _preparedname;
mapping(string:mixed) _tprepared;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected string _sprintf(int type, void|mapping flags) {
|
11b13b | 2014-08-16 | Martin Nilsson | | string res=UNDEFINED;
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | switch(type) {
case 'O':
res=sprintf("pgsql_result numrows: %d eof: %d inflight: %d\n"
#ifdef PG_DEBUGMORE
"query: %O\n"
#endif
"portalname: %O datarows: %d"
" laststatus: %s\n",
numrows,eoffound,_inflight,
#ifdef PG_DEBUGMORE
_query,
#endif
_portalname,sizeof(_datarowdesc),
_statuscmdcomplete||"");
break;
|
11b13b | 2014-08-16 | Martin Nilsson | | }
return res;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | void create(object pgsqlsess,PGassist _c,string query,
int portalbuffersize,int alltyped,array params,int forcetext) {
|
11b13b | 2014-08-16 | Martin Nilsson | | _pgsqlsess = pgsqlsess;
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | c = _c;
|
11b13b | 2014-08-16 | Martin Nilsson | | _query = query;
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | _datarows = Thread.Queue(); numrows = UNDEFINED;
closemux=Thread.Mutex();
|
11b13b | 2014-08-16 | Martin Nilsson | | _portalbuffersize=portalbuffersize;
_alltext = !alltyped;
_params = params;
_forcetext = forcetext;
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | _state = portalinit;
|
11b13b | 2014-08-16 | Martin Nilsson | | }
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | string status_command_complete() {
|
11b13b | 2014-08-16 | Martin Nilsson | | return _statuscmdcomplete;
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | int affected_rows() {
|
11b13b | 2014-08-16 | Martin Nilsson | | int rows;
if(_statuscmdcomplete)
sscanf(_statuscmdcomplete,"%*s %d",rows);
return rows;
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | int num_fields() {
|
11b13b | 2014-08-16 | Martin Nilsson | | return sizeof(_datarowdesc);
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | int num_rows() {
|
11b13b | 2014-08-16 | Martin Nilsson | | int numrows;
if(_statuscmdcomplete)
sscanf(_statuscmdcomplete,"%*s %d",numrows);
return numrows;
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected inline void trydelayederror() {
if(_delayederror)
throwdelayederror(this);
}
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | int eof() {
trydelayederror();
|
11b13b | 2014-08-16 | Martin Nilsson | | return eoffound;
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | array(mapping(string:mixed)) fetch_fields() {
trydelayederror();
|
11b13b | 2014-08-16 | Martin Nilsson | | return _datarowdesc+({});
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | void _openportal() {
_pgsqlsess->_portalsinflight++;
Thread.MutexKey lock=closemux->lock();
_state=bound;
lock=0;
_statuscmdcomplete=UNDEFINED;
}
int _closeportal(PGplugbuffer plugbuffer) {
int retval=0;
PD("%O Try Closeportal %d\n",_portalname,_state);
Thread.MutexKey lock=closemux->lock();
_fetchlimit=0;
switch(_state) {
case copyinprogress:
|
11b13b | 2014-08-16 | Martin Nilsson | | PD("CopyDone\n");
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | plugbuffer->add("c\0\0\0\4");
case bound:
_state=closed;
lock=0;
PD("Close portal %O\n",_portalname);
if(sizeof(_portalname)) {
plugbuffer->add_int8('C')->add_hstring(({'P',_portalname,0}),4,4);
retval=1;
} else
_unnamedportalkey=0;
if(!--_pgsqlsess->_portalsinflight) {
PD("Sync\n");
plugbuffer->add(PGSYNC);
_pgsqlsess->_pportalcount=0;
retval=2;
}
}
lock=0;
return retval;
}
final void _processdataready(int gfetchlimit) {
_rowsreceived++;
if(_rowsreceived==1)
PD("<%O _fetchlimit %d=min(%d||1,%d), _inflight %d\n",_portalname,
_fetchlimit,(_portalbuffersize>>1)*_rowsreceived/_bytesreceived,
gfetchlimit,_inflight);
if(_fetchlimit) {
_fetchlimit=
min((_portalbuffersize>>1)*_rowsreceived/_bytesreceived||1,gfetchlimit);
#if STREAMEXECUTES
Thread.MutexKey lock=closemux->lock();
if(_fetchlimit && _inflight<=_fetchlimit-1)
_sendexecute(_fetchlimit);
#ifdef PG_DEBUG
else if(!_fetchlimit)
PD("<%O _fetchlimit %d, _inflight %d, skip execute\n",
_portalname,_fetchlimit,_inflight);
#endif
lock=0;
#endif
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | }
void _releasesession() {
_inflight=0;
_datarows->write(1);
object plugbuffer=c->start(1);
plugbuffer->sendcmd(_closeportal(plugbuffer));
|
11b13b | 2014-08-16 | Martin Nilsson | | _pgsqlsess=UNDEFINED;
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | | }
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | protected void destroy() {
catch {
_releasesession();
|
11b13b | 2014-08-16 | Martin Nilsson | | };
}
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | | final void _sendexecute(int fetchlimit,void|PGplugbuffer plugbuffer) {
int flushmode;
PD("Execute portal %O fetchlimit %d\n",_portalname,fetchlimit);
if(!plugbuffer)
plugbuffer=c->start(1);
plugbuffer->add_int8('E')->add_hstring(_portalname,4,8+1)
->add_int8(0)->add_int32(fetchlimit);
if(!fetchlimit) {
_closeportal(plugbuffer);
flushmode=sendout;
} else
_inflight+=fetchlimit, flushmode=flushsend;
plugbuffer->sendcmd(flushmode,this);
|
11b13b | 2014-08-16 | Martin Nilsson | | }
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | |
array(mixed) fetch_row() {
int|array datarow;
if(arrayp(datarow=_datarows->try_read()))
return datarow;
if(!datarow && !eoffound
&& (
#ifdef PG_DEBUG
PD("%O Block for datarow\n",_portalname),
#endif
arrayp(datarow=_datarows->read())))
return datarow;
trydelayederror();
eoffound=1;
return 0;
}
array(array(mixed)) fetch_row_array() {
if(eoffound)
return 0;
array(array|int) datarow=_datarows->try_read_array();
if(!datarow)
datarow=_datarows->read_array();
if(arrayp(datarow[-1]))
return datarow;
trydelayederror();
eoffound=1;
return (datarow=datarow[..<1]);
}
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | |
|
cff3a3 | 2014-09-12 | Stephen R. van den Berg | |
void send_row(void|string|array(string) copydata) {
trydelayederror();
if(copydata) {
PD("CopyData\n");
c->start()->add_int8('d')->add_hstring(copydata,4,4)->sendcmd(sendout);
} else
_releasesession();
}
protected void run_result_cb(
function(pgsql_result, array(mixed), mixed ...:void) callback,
array(mixed) args) {
int|array datarow;
while(arrayp(datarow=_datarows->read_array()))
callback(this, datarow, @args);
trydelayederror();
eoffound=1;
callback(this, 0, @args);
}
void set_result_callback(
function(pgsql_result, array(mixed), mixed ...:void) callback,
mixed ... args) {
if(callback)
Thread.Thread(run_result_cb,callback,args);
}
protected void run_result_array_cb(
function(pgsql_result, array(array(mixed)), mixed ...:void) callback,
array(mixed) args) {
array(array|int) datarow;
while((datarow=_datarows->read_array()) && arrayp(datarow[-1]))
callback(this, datarow, @args);
trydelayederror();
eoffound=1;
if(sizeof(datarow)>1)
callback(this, datarow=datarow[..<1], @args);
callback(this, 0, @args);
}
void set_result_array_callback(
function(pgsql_result, array(array(mixed)), mixed ...:void) callback,
mixed ... args) {
if(callback)
Thread.Thread(run_result_array_cb,callback,args);
|
11b13b | 2014-08-16 | Martin Nilsson | | }
|
ecbab1 | 2008-07-27 | Stephen R. van den Berg | |
|
11b13b | 2014-08-16 | Martin Nilsson | | }
|