pike.git
/
lib
/
modules
/
Sql.pmod
/
pgsql_util.pmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1:
/* * Some pgsql utility functions. * They are kept here to avoid circular references. */ //! The pgsql backend, shared between all connection instances.
-
//! It runs even in non-callback mode in a separate thread.
+
//! It runs even in non-callback mode in a separate thread
and makes sure
+
//! that communication with the database is real-time and event driven
+
//! at all times
.
//! //! @note //! Callbacks running from this backend directly determine the latency //! in reacting to communication with the database server; so it //! would be prudent not to block in these callbacks. #pike __REAL_VERSION__ #require constant(Thread.Thread) #include "pgsql.h"
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:27:
=Regexp("^[ \t\f\r\n]*[Cc][Rr][Ee][Aa][Tt][Ee][ \t\f\r\n]"); private Regexp dontcacheprefix =Regexp("^[ \t\f\r\n]*([Ff][Ee][Tt][Cc][Hh]|[Cc][Oo][Pp][Yy])[ \t\f\r\n]"); private Regexp commitprefix=Regexp( "^[ \t\f\r\n]*([Cc][Oo][Mm][Mm][Ii][Tt]|[Ee][Nn][Dd])([ \t\f\r\n;]|$)"); private Regexp execfetchlimit =Regexp("^[ \t\f\r\n]*(([Uu][Pp][Dd][Aa]|[Dd][Ee][Ll][Ee])[Tt][Ee]|\ [Ii][Nn][Ss][Ee][Rr][Tt])[ \t\f\r\n]|\ [ \t\f\r\n][Ll][Ii][Mm][Ii][Tt][ \t\f\r\n]+[12][; \t\f\r\n]*$");
-
final void closestatement(
PGplugbuffer
|
PGassist
plugbuffer,string oldprep) {
+
final void closestatement(
bufcon
|
conxion
plugbuffer,string oldprep) {
if(oldprep) { PD("Close statement %s\n",oldprep); plugbuffer->add_int8('C')->add_hstring(({'S',oldprep,0}),4,4); } } private void run_local_backend() { Thread.MutexKey lock; int looponce; do {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:93:
case MACADDROID: case BPCHAROID: case VARCHAROID: case CTIDOID: case UUIDOID: return 1; //binary } return 0; // text }
-
private sctype mergemode(
PGassist
realbuffer,sctype mode) {
+
private sctype mergemode(
conxion
realbuffer,sctype mode) {
if(mode>realbuffer->stashflushmode) realbuffer->stashflushmode=mode; return realbuffer->stashflushmode; } private inline mixed callout(function(mixed ...:void) f, float|int delay,mixed ... args) { return local_backend->call_out(f,delay,@args); } // Some pgsql utility functions
-
class
PGplugbuffer
{
+
class
bufcon
{
inherit Stdio.Buffer;
-
private
PGassist
realbuffer;
+
private
conxion
realbuffer;
-
protected void create(
PGassist
_realbuffer) {
+
protected void create(
conxion
_realbuffer) {
realbuffer=_realbuffer; }
-
final
PGplugbuffer
start(void|int waitforreal) {
+
final
bufcon
start(void|int waitforreal) {
realbuffer->stashcount++; #ifdef PG_DEBUG if(waitforreal)
-
error("pgsql.
PGplugbuffer
not allowed here\n");
+
error("pgsql.
bufcon
not allowed here\n");
#endif return this; }
-
final void sendcmd(void|sctype mode,void|
pgsql
_result portal) {
+
final void sendcmd(void|sctype mode,void|
sql
_result 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); } } }
-
class
PGassist
{
+
class
conxion
{
inherit Stdio.Buffer:i; inherit Stdio.Buffer:o; private Thread.Condition fillread; private Thread.Mutex fillreadmux; private Thread.Queue qportals; final Stdio.File socket; private object pgsqlsess; private int towrite;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:169:
final Thread.Condition stashavail; final Stdio.Buffer stash; final int stashflushmode; final int stashcount; final int synctransact; #ifdef PG_DEBUG final int queueoutidx; final int queueinidx=-1; #endif
-
private inline void queueup(
pgsql
_result portal) {
+
private inline void queueup(
sql
_result portal) {
qportals->write(portal); portal->_synctransact=synctransact; PD(">%O %d %d Queue portal %d bytes\n",portal._portalname,++queueoutidx, synctransact,sizeof(this)); }
-
final
PGassist
|
PGplugbuffer
start(void|int waitforreal) {
+
final
conxion
|
bufcon
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 portal)
+
foreach(stashqueue->try_read_array();;
sql
_result portal)
queueup(portal); lock=0; return this; } stashcount++;
-
return
PGplugbuffer
(this);
+
return
bufcon
(this);
} protected bool range_error(int howmuch) { if(!howmuch) return false; #ifdef PG_DEBUG if(howmuch<0) error("Out of range %d\n",howmuch); #endif if(fillread) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:235:
final inline int consume(int w) { return i::consume(w); } final inline int unread(int w) { return i::unread(w); } final inline string read(int w) { return i::read(w); } final inline object read_buffer(int w) { return i::read_buffer(w); } final inline int read_sint(int w) { return i::read_sint(w); } final inline int read_int8() { return i::read_int8(); } final inline int read_int16() { return i::read_int16(); } final inline int read_int32() { return i::read_int32(); } final inline string read_cstring() { return i::read_cstring(); }
-
final void sendcmd(void|sctype mode,void|
pgsql
_result portal) {
+
final void sendcmd(void|sctype mode,void|
sql
_result portal) {
if(portal) queueup(portal); nosync: do { switch(mode) { default: break nosync; case syncsend: PD(">Sync %d %d Queue\n",synctransact,++queueoutidx); add(PGSYNC);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:259:
PD(">%O %d Queue simplequery %d bytes\n",portal._portalname, ++queueoutidx,sizeof(this)); mode=flushsend; } qportals->write(synctransact++); } while(0); if(started) { Thread.MutexKey lock=stashupdate->lock(); if(sizeof(stash)) { add(stash); stash->clear();
-
foreach(stashqueue->try_read_array();;
pgsql
_result portal)
+
foreach(stashqueue->try_read_array();;
sql
_result portal)
queueup(portal); } mode=mergemode(this,mode); stashflushmode=keep; lock=0; } catch { outer: do { switch(mode) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:353:
return; }; if(pgsqlsess) pgsqlsess->_connectfail(err); } private string _sprintf(int type, void|mapping flags) { string res=UNDEFINED; switch(type) { case 'O':
-
res=predef::sprintf("
PGassist
fd: %d input queue: %d/%d "
+
res=predef::sprintf("
conxion
fd: %d input queue: %d/%d "
"queued portals: %d output queue: %d/%d\n", socket&&socket->query_fd(), sizeof(i::this),i::_size_object(), qportals->size(),sizeof(this),_size_object()); break; } return res; } protected void create(object _pgsqlsess,Thread.Queue _qportals,int nossl) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:387:
pgsqlsess=_pgsqlsess; Thread.Thread(connectloop,nossl); } } //! The result object returned by @[Sql.pgsql()->big_query()], except for //! the noted differences it behaves the same as @[Sql.sql_result]. //! //! @seealso //! @[Sql.sql_result], @[Sql.pgsql], @[Sql.Sql], @[Sql.pgsql()->big_query()]
-
class
pgsql
_result {
+
class
sql
_result {
private object pgsqlsess; private int numrows; private int eoffound;
-
private
PGassist
c;
+
private
conxion
c;
final mixed _delayederror; final portalstate _state; final int _fetchlimit; final int _alltext; final int _forcetext; final string _portalname; final int _bytesreceived; final int _rowsreceived;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:426:
private Stdio.Buffer prepbuffer; private Thread.Condition prepbufferready; private Thread.Mutex prepbuffermux; final string _preparedname; final mapping(string:mixed) _tprepared; private string _sprintf(int type, void|mapping flags) { string res=UNDEFINED; switch(type) { case 'O':
-
res=sprintf("
pgsql
_result numrows: %d eof: %d inflight: %d\n"
+
res=sprintf("
sql
_result numrows: %d eof: %d inflight: %d\n"
"query: %O\n" "portalname: %O datarows: %d" " laststatus: %s\n", numrows,eoffound,_inflight, _query, _portalname,_datarowdesc&&sizeof(_datarowdesc), _statuscmdcomplete||""); break; } return res; }
-
protected void create(object _pgsqlsess,
PGassist
_c,string query,
+
protected void create(object _pgsqlsess,
conxion
_c,string query,
int portalbuffersize,int alltyped,array params,int forcetext) { pgsqlsess = _pgsqlsess; c = _c; _query = query; _datarows = Thread.Queue(); numrows = UNDEFINED; _ddescribe=Thread.Condition(); _ddescribemux=Thread.Mutex(); closemux=Thread.Mutex(); prepbufferready=Thread.Condition(); prepbuffermux=Thread.Mutex();
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:715:
pgsqlsess->_waittocommit++; PD("Commit waiting for portals to finish\n"); pgsqlsess->_readyforcommit->wait(lock); pgsqlsess->_waittocommit--; } lock=0; } PD("Bind portal %O statement %O\n",_portalname,_preparedname); _fetchlimit=pgsqlsess->_fetchlimit; _openportal();
-
PGassist
bindbuffer=c->start(1);
+
conxion
bindbuffer=c->start(1);
_unnamedstatementkey=0; bindbuffer->add_int8('B')->add_hstring(plugbuffer,4,4); if(!_tprepared) closestatement(bindbuffer,_preparedname); _sendexecute(pgsqlsess->_fetchlimit && !(cachealways[_query] || sizeof(_query)>=MINPREPARELENGTH && execfetchlimit->match(_query)) && FETCHLIMITLONGRUN,bindbuffer); }
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:750:
case copyinprogress: case bound: _datarows->write(1); // Signal EOF --pgsqlsess->_portalsinflight; } _state=closed; lock=0; releaseconditions(); }
-
final sctype _closeportal(
PGplugbuffer
plugbuffer) {
+
final sctype _closeportal(
bufcon
plugbuffer) {
sctype retval=keep; PD("%O Try Closeportal %d\n",_portalname,_state); Thread.MutexKey lock=closemux->lock(); _fetchlimit=0; // disables further Executes int alreadyfilled=sizeof(plugbuffer); /* alreadyfilled will be non-zero if a parse request has been queued * before the close was initiated. * It's a bit of a tricky race, but this check should be sufficient. */ switch(_state) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:831:
lock=_ddescribemux->lock(); _ddescribe->broadcast(); _datarowdesc=({}); } lock=0; } final void _releasesession() { _inflight=0; _datarows->write(1); // Signal EOF
-
PGassist
plugbuffer=c->start(1);
+
conxion
plugbuffer=c->start(1);
plugbuffer->sendcmd(_closeportal(plugbuffer)); releaseconditions(); } protected void destroy() { catch { // inside destructors, exceptions don't work _releasesession(); }; }
-
final void _sendexecute(int fetchlimit,void|
PGplugbuffer
plugbuffer) {
+
final void _sendexecute(int fetchlimit,void|
bufcon
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) flushmode=_closeportal(plugbuffer)==syncsend?syncsend:flushsend; else _inflight+=fetchlimit, flushmode=flushsend;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:924:
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(); } private void run_result_cb(
-
function(
pgsql
_result, array(mixed), mixed ...:void) callback,
+
function(
sql
_result, array(mixed), mixed ...:void) callback,
array(mixed) args) { int|array datarow; while(arrayp(datarow=_datarows->read_array())) callout(callback, 0, this, datarow, @args); trydelayederror(); eoffound=1; callout(callback, 0, this, 0, @args); } //! Sets up a callback for every row returned from the database. //! First argument passed is the resultobject itself, second argument //! is the result row (zero on EOF). //! //! @seealso //! @[fetch_row()] void set_result_callback(
-
function(
pgsql
_result, array(mixed), mixed ...:void) callback,
+
function(
sql
_result, array(mixed), mixed ...:void) callback,
mixed ... args) { if(callback) Thread.Thread(run_result_cb,callback,args); } private void run_result_array_cb(
-
function(
pgsql
_result, array(array(mixed)), mixed ...:void) callback,
+
function(
sql
_result, array(array(mixed)), mixed ...:void) callback,
array(mixed) args) { array(array|int) datarow; while((datarow=_datarows->read_array()) && arrayp(datarow[-1])) callout(callback, 0, this, datarow, @args); trydelayederror(); eoffound=1; if(sizeof(datarow)>1) callout(callback, 0, this, datarow=datarow[..<1], @args); callout(callback, 0, this, 0, @args); } //! Sets up a callback for sets of rows returned from the database. //! First argument passed is the resultobject itself, second argument //! is the array of result rows (zero on EOF). //! //! @seealso //! @[fetch_row()] void set_result_array_callback(
-
function(
pgsql
_result, array(array(mixed)), mixed ...:void) callback,
+
function(
sql
_result, array(array(mixed)), mixed ...:void) callback,
mixed ... args) { if(callback) Thread.Thread(run_result_array_cb,callback,args); } }