pike.git / lib / modules / Sql.pmod / pgsql_util.pmod

version» Context lines:

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);    }      }