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

version» Context lines:

pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:42:    PD("Starting local backend\n");    while(clientsregistered) // Autoterminate when not needed    local_backend(4096.0);    PD("Terminating local backend\n");    lock=0;    looponce=clientsregistered;    }    } while(looponce);   }    - protected void create() { - } -  +    final void register_backend() {    if(!clientsregistered++)    Thread.Thread(run_local_backend);   }      final void unregister_backend() {    --clientsregistered;   }      final void throwdelayederror(object parent) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:97:    return realbuffer->stashflushmode;   }      //! Some pgsql utility functions      class PGplugbuffer {    inherit Stdio.Buffer;       protected PGassist realbuffer;    -  final void create(PGassist _realbuffer) { +  protected void create(PGassist _realbuffer) {    realbuffer=_realbuffer;    }       final PGplugbuffer start(void|int waitforreal) {    realbuffer->stashcount++;   #ifdef PG_DEBUG    if(waitforreal)    error("pgsql.PGplugbuffer not allowed here\n");   #endif    return this;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:137:   }      class PGassist {    inherit Stdio.Buffer:i;    inherit Stdio.Buffer:o;       protected Thread.Condition fillread;    protected Thread.Mutex fillreadmux;    protected Thread.Queue qportals;    final Stdio.File socket; +  protected object pgsqlsess;    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; -  int synctransact; +  final Thread.Mutex nostash; +  final Thread.MutexKey started; +  final Thread.Mutex stashupdate; +  final Thread.Queue stashqueue; +  final Thread.Condition stashavail; +  final Stdio.Buffer stash; +  final int stashflushmode; +  final int stashcount; +  final int synctransact;   #ifdef PG_DEBUG -  int queueoutidx; -  int queueinidx; +  final int queueoutidx; +  final int queueinidx;   #endif       inline void queueup(pgsql_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) {    Thread.MutexKey lock;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:241:    Thread.MutexKey lock=stashupdate->lock();    if(sizeof(stash)) {    add(stash); stash->clear();    foreach(stashqueue->try_read_array();;pgsql_result portal)    queueup(portal);    }    mode=mergemode(this,mode);    stashflushmode=keep;    lock=0;    } +  catch {   outer:    do {    switch(mode) {    default:    break outer;    case syncsend:    PD(">Sync %d %d Queue\n",synctransact,++queueoutidx);    qportals->write(synctransact++); add(PGSYNC);    break;    case flushsend:    PD("Flush\n");    add(PGFLUSH);    case sendout:;    }    if(towrite=sizeof(this)) {    PD(">Sendcmd %O\n",((string)this)[..towrite-1]);    towrite-=output_to(socket,towrite);    }    } while(0);    started=0; -  +  return; +  }; +  pgsqlsess->_connectfail();    }       final void sendterminate() {    destruct(fillread); // Delayed close() after flushing the output buffer    }       final int close() {    return socket->close();    }       final void destroy() {    catch(close()); // Exceptions don't work inside destructors -  +  pgsqlsess=0;    }    -  final void connectloop(object pgsqlsess,int nossl) { +  final void connectloop(int nossl) {    mixed err=catch {    for(;;clear()) {    socket->connect(pgsqlsess._host,pgsqlsess._port);   #if constant(SSL.File)    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()) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:309: Inside #if constant(SSL.File)
   }    }   #else    if(pgsqlsess.options.force_ssl)    error("Encryption library missing,"    " cannot establish connection to %s:%d\n",    pgsqlsess.host,pgsqlsess.port);   #endif    break;    } +  if(!socket->is_open()) +  error(strerror(socket->errno()));    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) { +  protected void create(object _pgsqlsess,Thread.Queue _qportals,int nossl) {    i::create(); o::create();    qportals = _qportals;    synctransact = 1;    fillread=Thread.Condition();    fillreadmux=Thread.Mutex();    gottimeout=sendcmd; // Preset it with a NOP    timeout=128; // Just a reasonable amount    socket=Stdio.File();    nostash=Thread.Mutex();    stashupdate=Thread.Mutex();    stashqueue=Thread.Queue();    stashavail=Thread.Condition();    stash=Stdio.Buffer(); -  Thread.Thread(connectloop,pgsqlsess,nossl); +  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 {    -  object _pgsqlsess; +  protected object pgsqlsess;    protected int numrows;    protected int eoffound;    protected PGassist c; -  mixed _delayederror; -  portalstate _state; -  int _fetchlimit; -  int _alltext; -  int _forcetext; +  final mixed _delayederror; +  final portalstate _state; +  final int _fetchlimit; +  final int _alltext; +  final int _forcetext;    -  string _portalname; +  final string _portalname;    -  int _bytesreceived; -  int _rowsreceived; -  int _inflight; -  int _portalbuffersize; -  int _synctransact; -  Thread.Condition _ddescribe; -  Thread.Mutex _ddescribemux; -  Thread.MutexKey _unnamedportalkey,_unnamedstatementkey; +  final int _bytesreceived; +  final int _rowsreceived; +  final int _inflight; +  final int _portalbuffersize; +  final int _synctransact; +  final Thread.Condition _ddescribe; +  final Thread.Mutex _ddescribemux; +  final Thread.MutexKey _unnamedportalkey,_unnamedstatementkey;    protected Thread.Mutex closemux; -  array _params; -  string _statuscmdcomplete; -  string _query; -  Thread.Queue _datarows; -  array(mapping(string:mixed)) _datarowdesc; -  int _oldpbpos; -  object _plugbuffer; -  string _preparedname; -  mapping(string:mixed) _tprepared; +  final array _params; +  final string _statuscmdcomplete; +  final string _query; +  final Thread.Queue _datarows; +  final array(mapping(string:mixed)) _datarowdesc; +  final int _oldpbpos; +  protected object prepbuffer; +  protected Thread.Condition prepbufferready; +  protected Thread.Mutex prepbuffermux; +  final string _preparedname; +  final mapping(string:mixed) _tprepared;       protected 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"   #ifdef PG_DEBUGMORE    "query: %O\n"   #endif    "portalname: %O datarows: %d"
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:395: Inside #if defined(PG_DEBUGMORE)
  #ifdef PG_DEBUGMORE    _query,   #endif    _portalname,_datarowdesc&&sizeof(_datarowdesc),    _statuscmdcomplete||"");    break;    }    return res;    }    -  void create(object pgsqlsess,PGassist _c,string query, +  protected void create(object _pgsqlsess,PGassist _c,string query,    int portalbuffersize,int alltyped,array params,int forcetext) { -  _pgsqlsess = pgsqlsess; +  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();    _portalbuffersize=portalbuffersize;    _alltext = !alltyped;    _params = params;    _forcetext = forcetext;    _state = portalinit;    }       //! Returns the command-complete status for this query.    //!    //! @seealso
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:499:    final void _preparebind(array dtoid) {    array(string|int) paramValues=_params?_params[2]:({});    if(sizeof(dtoid)!=sizeof(paramValues))    SUSERERROR("Invalid number of bindings, expected %d, got %d\n",    sizeof(dtoid),sizeof(paramValues));   #ifdef PG_DEBUGMORE    PD("ParamValues to bind: %O\n",paramValues);   #endif    object plugbuffer=Stdio.Buffer();    plugbuffer->add(_portalname= -  (_unnamedportalkey=_pgsqlsess._unnamedportalmux->trylock(1)) -  ? "" : PORTALPREFIX+int2hex(_pgsqlsess._pportalcount++) )->add_int8(0) +  (_unnamedportalkey=pgsqlsess._unnamedportalmux->trylock(1)) +  ? "" : PORTALPREFIX+int2hex(pgsqlsess._pportalcount++) )->add_int8(0)    ->add(_preparedname)->add_int8(0)->add_int16(sizeof(paramValues));    foreach(dtoid;;int textbin)    plugbuffer->add_int16(oidformat(textbin));    plugbuffer->add_int16(sizeof(paramValues)); -  string cenc=_pgsqlsess._runtimeparameter[CLIENT_ENCODING]; +  string cenc=pgsqlsess._runtimeparameter[CLIENT_ENCODING];    foreach(paramValues;int i;mixed value) {    if(undefinedp(value))    plugbuffer->add_int32(-1); // NULL    else if(stringp(value) && !sizeof(value)) {    int k=0;    switch(dtoid[i]) {    default:    k=-1; // cast empty strings to NULL for non-string types    case BYTEAOID:    case TEXTOID:
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:618:    break;    case OIDOID:    case INT4OID:    plugbuffer->add_int32(4)->add_int32((int)value);    break;    case INT2OID:    plugbuffer->add_int32(2)->add_int16((int)value);    break;    }    } -  _plugbuffer=plugbuffer; +  prepbuffer=plugbuffer; +  int skipsignal=0;    if(_tprepared)    if(_tprepared.datarowdesc) -  _dodatarows(); +  skipsignal=1, gotdatarowdesc();    else if(dontcacheprefix->match(_query)) // Don't cache FETCH/COPY -  m_delete(_pgsqlsess->_prepareds,_query),_tprepared=0; +  m_delete(pgsqlsess->_prepareds,_query),_tprepared=0; +  if(!skipsignal) { +  Thread.MutexKey lock=prepbuffermux->lock(); +  prepbufferready->signal(); +  lock=0;    } -  +  }       final void _processrowdesc(array(mapping(string:mixed)) datarowdesc) {    _setrowdesc(datarowdesc);    mapping(string:mixed) tp=_tprepared; // FIXME Is caching this worthwhile?    if(!tp || !tp.datarowdesc) -  Thread.Thread(_dodatarows,this); +  Thread.Thread(gotdatarowdesc);    if(tp)    tp.datarowdesc=datarowdesc;    }    -  final void _dodatarows() { -  object plugbuffer=_plugbuffer; -  _plugbuffer=0; +  protected void gotdatarowdesc() { +  if(!prepbuffer) { +  Thread.MutexKey lock=prepbuffermux->lock(); +  prepbufferready->wait(lock); +  lock=0; +  } +  object plugbuffer=prepbuffer; +  prepbuffer=0;    plugbuffer->add_int16(sizeof(_datarowdesc));    foreach(_datarowdesc;;mapping col)    plugbuffer->add_int16(oidformat(col.type));    PD("Bind portal %O statement %O\n",_portalname,_preparedname); -  _fetchlimit=_pgsqlsess->_fetchlimit; +  _fetchlimit=pgsqlsess->_fetchlimit;    _openportal();    object bindbuffer=c->start(1);    _unnamedstatementkey=0;    bindbuffer->add_int8('B')->add_hstring(plugbuffer,4,4);    if(!_tprepared)    closestatement(bindbuffer,_preparedname); -  _sendexecute(_pgsqlsess->_fetchlimit +  _sendexecute(pgsqlsess->_fetchlimit    && !(cachealways[_query]    || sizeof(_query)>=MINPREPARELENGTH &&    execfetchlimit->match(_query))    && FETCHLIMITLONGRUN,bindbuffer);    }       final void _openportal() { -  _pgsqlsess->_portalsinflight++; +  pgsqlsess->_portalsinflight++;    Thread.MutexKey lock=closemux->lock();    _state=bound;    lock=0;    _statuscmdcomplete=UNDEFINED;    }       final void _purgeportal() {    _unnamedportalkey=0;    Thread.MutexKey lock=closemux->lock();    _fetchlimit=0; // disables further Executes    switch(_state) {    case copyinprogress:    case bound: -  --_pgsqlsess->_portalsinflight; +  --pgsqlsess->_portalsinflight;    }    _state=closed;    lock=0;    }       final sctype _closeportal(PGplugbuffer plugbuffer) {    sctype retval=keep;    PD("%O Try Closeportal %d\n",_portalname,_state);    Thread.MutexKey lock=closemux->lock();    _fetchlimit=0; // disables further Executes
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:698:    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=flushsend;    } else    _unnamedportalkey=0; -  if(!--_pgsqlsess->_portalsinflight) { -  _pgsqlsess->_readyforquerycount++; -  _pgsqlsess->_pportalcount=0; +  if(!--pgsqlsess->_portalsinflight) { +  pgsqlsess->_readyforquerycount++; +  pgsqlsess->_pportalcount=0;    retval=syncsend;    }    }    lock=0;    return retval;    }       final void _processdataready() {    _rowsreceived++;    if(_rowsreceived==1)    PD("<%O _fetchlimit %d=min(%d||1,%d), _inflight %d\n",_portalname,    _fetchlimit,(_portalbuffersize>>1)*_rowsreceived/_bytesreceived, -  _pgsqlsess._fetchlimit,_inflight); +  pgsqlsess._fetchlimit,_inflight);    if(_fetchlimit) {    _fetchlimit=    min((_portalbuffersize>>1)*_rowsreceived/_bytesreceived||1, -  _pgsqlsess._fetchlimit); +  pgsqlsess._fetchlimit);    Thread.MutexKey lock=closemux->lock();    if(_fetchlimit && _inflight<=_fetchlimit-1)    _sendexecute(_fetchlimit);    else if(!_fetchlimit)    PD("<%O _fetchlimit %d, _inflight %d, skip execute\n",    _portalname,_fetchlimit,_inflight);    lock=0;    }    }       final void _releasesession() {    _inflight=0;    _datarows->write(1); // Signal EOF    object plugbuffer=c->start(1);    plugbuffer->sendcmd(_closeportal(plugbuffer)); -  _pgsqlsess=UNDEFINED; +  pgsqlsess=UNDEFINED;    }       protected void destroy() {    catch { // inside destructors, exceptions don't work    _releasesession();    };    }       final void _sendexecute(int fetchlimit,void|PGplugbuffer plugbuffer) {    int flushmode;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:798:    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; +  _datarows->write(1); // Signal EOF for other threads    return (datarow=datarow[..<1]);    }       //! @param copydatasend    //! When using COPY FROM STDIN, this method accepts a string or an    //! array of strings to be processed by the COPY command; when sending    //! the amount of data sent per call does not have to hit row or column    //! boundaries.    //!    //! The COPY FROM STDIN sequence needs to be completed by either