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

version» Context lines:

pike.git/lib/modules/Sql.pmod/pgsql.pike:262:   //! and that the other end hasn't closed it yet. No data is   //! sent over the connection.   //!   //! For a more reliable check of whether the connection   //! is alive, please use @[ping()].   //!   //! @seealso   //! @[ping()]   int is_open() {    catch { -  return c->socket->query_fd()>=0; +  return c->socket->is_open();    };    return 0;   }      //! @decl int ping()   //!   //! Check whether the connection is alive.   //!   //! @returns   //! Returns one of the following:
pike.git/lib/modules/Sql.pmod/pgsql.pike:312:    PD("CancelRequest\n");    object lcon=getsocket(1);    lcon->add_int32(16)->add_int32(PG_PROTOCOL(1234,5678))    ->add_int32(backendpid)->add(cancelsecret)->sendcmd(flushsend);    lcon->close();   #ifdef PG_DEBUGMORE    PD("Closetrace %O\n",backtrace());   #endif    object plugbuffer=c->start(1);    foreach(qportals->peek_array();;object portal) +  if(objectp(portal))    portal->_closeportal(plugbuffer);    plugbuffer->sendcmd(sendout);   }      //! Changes the connection charset. When set to @expr{"UTF8"@}, the query,   //! parameters and results can be Pike-native wide strings.   //!   //! @param charset   //! A PostgreSQL charset name.   //!
pike.git/lib/modules/Sql.pmod/pgsql.pike:569:   }      protected void storetiming(object portal) {    mapping(string:mixed) tp=portal._tprepared;    tp.trun=gethrtime()-tp.trunstart;    m_delete(tp,"trunstart");    portal._tprepared = UNDEFINED;   }      final void _processloop(object ci) { -  int die=0,terminating=0; +  int terminating=0;    int|.pgsql_util.pgsql_result portal;    mixed err;    {    object plugbuffer=Stdio.Buffer()->add_int32(PG_PROTOCOL(3,0));    if(user)    plugbuffer->add("user\0")->add(user)->add_int8(0);    if(database)    plugbuffer->add("database\0")->add(database)->add_int8(0);    options->reconnect=undefinedp(options->reconnect) || options->reconnect;    foreach(options
pike.git/lib/modules/Sql.pmod/pgsql.pike:783: Inside #if defined(PG_DEBUG)
   msglen-=4+1;    PD("<ReadyForQuery %c\n",backendstatus);   #endif    for(;objectp(portal);portal->read()) {   #ifdef PG_DEBUG    showportal(msgtype);   #endif    portal->_purgeportal();    }    foreach(qportals->peek_array();;.pgsql_util.pgsql_result qp) { +  if(objectp(qp) && qp._synctransact && qp._synctransact<=portal) {    PD("Checking portal %O %d<=%d\n",    qp._portalname,qp._synctransact,portal); -  if(qp._synctransact && qp._synctransact<=portal) +     qp->_purgeportal();    } -  +  }    portal=0;    _readyforquerycount--;    if(readyforquery_cb)    readyforquery_cb(),readyforquery_cb=0;    if(waitforauthready)    destruct(waitforauthready);    break;    case '1':   #ifdef PG_DEBUG    PD("<ParseComplete\n");
pike.git/lib/modules/Sql.pmod/pgsql.pike:815: Inside #if defined(PG_DEBUG)
   PD("<%O ParameterDescription %d values\n",portal._query,cols);    msglen-=4+2+4*cols;   #endif    foreach(a=allocate(cols);int i;)    a[i]=ci->read_int32();   #ifdef PG_DEBUGMORE    PD("%O\n",a);   #endif    if(portal._tprepared)    portal._tprepared.datatypeoid=a; -  portal->_preparebind(a); +  Thread.Thread(portal->_preparebind,a);    break;    }    case 'T': {    array a;   #ifdef PG_DEBUG    int cols=ci->read_int16();    PD("<RowDescription %d columns %O\n",cols,portal._query);    msglen-=4+2;    foreach(a=allocate(cols);int i;)   #else
pike.git/lib/modules/Sql.pmod/pgsql.pike:858: Inside #if defined(PG_DEBUG)
   */    res.formatcode=ci->read_int16();   #else    ci->consume(8);   #endif    a[i]=res;    }   #ifdef PG_DEBUGMORE    PD("%O\n",a);   #endif +  if(portal._forcetext) +  portal->_setrowdesc(a); // Do not consume queued portal +  else {    portal->_processrowdesc(a);    portal=0; -  +  }    break;    }    case 'n': {   #ifdef PG_DEBUG    msglen-=4;    PD("<NoData %O\n",portal._query);   #endif    portal._fetchlimit=0; // disables subsequent Executes    portal->_processrowdesc(({}));    portal=0;
pike.git/lib/modules/Sql.pmod/pgsql.pike:908:    tp.trunstart=tend;    }    }    break;    }    case 'D': {    msglen-=4;    string serror;    if(portal._tprepared)    storetiming(portal); -  array a, datarowdesc; +     portal._bytesreceived+=msglen; -  datarowdesc=portal._datarowdesc; +  array datarowdesc=portal._datarowdesc;    int cols=ci->read_int16();   #ifdef PG_DEBUG   #ifdef PG_DEBUGMORE    PD("<%O DataRow %d cols %d bytes\n",portal._portalname,cols,msglen);   #endif    datarowdebugcount++;    if(!datarowdebug)    datarowdebug=sprintf(    "<%O DataRow %d cols %d bytes",portal._portalname,cols,msglen);   #endif    int atext = portal._alltext; // cache locally for speed    int forcetext = portal._forcetext; // cache locally for speed    string cenc=_runtimeparameter[CLIENT_ENCODING]; -  a=allocate(cols,UNDEFINED); +  array a=allocate(cols,UNDEFINED);    msglen-=2+4*cols;    foreach(datarowdesc;int i;mapping m) {    int collen=ci->read_sint(4);    if(collen>0) {    msglen-=collen;    mixed value;    switch(int typ=m.type) {    case FLOAT4OID:   #if SIZEOF_FLOAT>=8    case FLOAT8OID:
pike.git/lib/modules/Sql.pmod/pgsql.pike:1081:    mapping(string:string) msgresponse;    msgresponse=getresponse();    warningsdropcount+=warningscollected;    warningscollected=0;    switch(msgresponse.C) {    case "P0001":    lastmessage=({sprintf("%s: %s",msgresponse.S,msgresponse.M)});    USERERROR(a2nls(lastmessage    +({pinpointerror(portal._query,msgresponse.P)})    +showbindings(portal))); -  case "57P01":case "57P02":case "57P03":die=1; +  case "57P01":case "57P02":case "57P03":    preplastmessage(msgresponse); -  PD(a2nls(lastmessage));USERERROR(a2nls(lastmessage)); +  PD(a2nls(lastmessage));throw(0);    case "08P01":case "42P05":    errtype=protocolerror;    case "XX000":case "42883":case "42P01":    invalidatecache=1;    default:    preplastmessage(msgresponse);    if(msgresponse.D)    lastmessage+=({msgresponse.D});    if(msgresponse.H)    lastmessage+=({msgresponse.H});
pike.git/lib/modules/Sql.pmod/pgsql.pike:1158:    default:    if(msgtype!=-1) {    string s;    PD("Unknown message received %c\n",msgtype);    s=ci->read(msglen-=4);PD("%O\n",s);   #ifdef PG_DEBUG    msglen=0;   #endif    errtype=protocolunsupported;    } else { -  if(!waitforauthready) -  die=1; +     lastmessage+=({    sprintf("Connection lost to database %s@%s:%d/%s %d\n",    user,_host,_port,database,backendpid)}); -  +  if(!waitforauthready) +  throw(0);    USERERROR(a2nls(lastmessage));    }    break;    }   #ifdef PG_DEBUG    if(msglen)    errtype=protocolerror;   #endif    {    string msg;
pike.git/lib/modules/Sql.pmod/pgsql.pike:1194:    }    }; // We only get here if there is an error    if(err==MAGICTERMINATE) {    ci->start()->add("X\0\0\0\4")->sendcmd(sendout);    terminating=1;    if(!sizeof(ci))    break;    }    if(stringp(err)) {    .pgsql_util.pgsql_result or; -  if(!(or=portal)) +  if(!objectp(or=portal))    or=this;    if(!or._delayederror)    or._delayederror=err; -  if(portal) +  if(objectp(portal))    portal->_releasesession();    portal=0;    continue;    }    break;    }    _delayederror=err;    if(!ci->close() && !terminating && options.reconnect)    _connectfail(); -  +  if(err)    throw(err);   }      //! Closes the connection to the database, any running queries are   //! terminated instantly.   //!   //! @note   //! This function is PostgreSQL-specific, and thus it is not available   //! through the generic SQL-interface.   void close() {
pike.git/lib/modules/Sql.pmod/pgsql.pike:1230:    c->sendterminate();    c=0;   }      void destroy() {    close();    .pgsql_util.unregister_backend();   }      void _connectfail(void|mixed err) { -  if(err) -  _delayederror=err; +  PD("Connect failed %O reconnectdelay %d\n",err,reconnectdelay);    if(!err || reconnectdelay) {    int tdelay;    switch(tdelay=reconnectdelay) {    case 0:    reconnectdelay=RECONNECTDELAY;    break;    default: -  +  if(err) +  _delayederror=err;    if(options.reconnect!=-1)    return;    reconnectdelay=RECONNECTBACKOFF;    break;    }    Thread.MutexKey lock=waitforauth->lock();    if(!waitforauthready)    waitforauthready=Thread.Condition();    lock=0; -  +  PD("Schedule reconnect in %ds\n",tdelay); +  _delayederror=0;    .pgsql_util.local_backend->call_out(reconnect,tdelay,1); -  +  } else if(err) +  _delayederror=err;   } - } +       protected int reconnect(void|int force,void|object tt) { -  +  PD("(Re)connect\n");    if(!force) {    Thread.MutexKey lock=waitforauth->lock();    if(waitforauthready) {    lock=0;    return 0; // Connect still in progress in other thread    }    waitforauthready=Thread.Condition();    lock=0;    }    if(c) { -  +  PD("Close old connection\n");    reconnected++;   #ifdef PG_STATS    prepstmtused=0;   #endif    if(!force)    c->sendterminate();    else    c->close();    c=0; -  +  PD("Flushing old cache\n");    foreach(_prepareds;;mapping tp)    m_delete(tp,"preparedname");    if(!options.reconnect)    return 0;    } -  +  PD("Actually start to connect\n");    qportals=Thread.Queue();    _readyforquerycount=1;    qportals->write(1);    if(!(c=getsocket())) {    string msg=sprintf("Couldn't connect to database on %s:%d",_host,_port);    if(force) {    if(!sizeof(lastmessage) || lastmessage[sizeof(lastmessage)-1]!=msg)    lastmessage+=({msg});    return 0;    } else
pike.git/lib/modules/Sql.pmod/pgsql.pike:1707:   }      final inline void closestatement(object plugbuffer,string oldprep) {    .pgsql_util.closestatement(plugbuffer,oldprep);   }      protected inline string int2hex(int i) {    return String.int2hex(i);   }    - final void throwdelayederror(object parent) { + final inline void throwdelayederror(object parent) {    .pgsql_util.throwdelayederror(parent);   }      //! @decl Sql.pgsql_util.pgsql_result big_query(string query)   //! @decl Sql.pgsql_util.pgsql_result big_query(string query, mapping bindings)   //!   //! This is the only provided interface which allows you to query the   //! database. If you wish to use the simpler @[Sql.Sql()->query()] function,   //! you need to use the @[Sql.Sql] generic SQL-object.   //!
pike.git/lib/modules/Sql.pmod/pgsql.pike:1777:    case UTF8CHARSET:    q=string_to_utf8(q);    break;    default:    if(String.width(q)>8)    ERROR("Don't know how to convert %O to %s encoding\n",q,cenc);    }    array(string|int) paramValues;    array from;    if(bindings) { +  if(forcetext) +  q = .sql_util.emulate_bindings(q, bindings, this), paramValues=({}); +  else {    int pi=0,rep=0;    paramValues=allocate(sizeof(bindings));    from=allocate(sizeof(bindings));    array(string) to=allocate(sizeof(bindings));    foreach(bindings; mixed name; mixed value) {    if(stringp(name)) { // Throws if mapping key is empty string    if(name[0]!=':')    name=":"+name;    if(name[1]=='_') { // Special option parameter    switch(name) {
pike.git/lib/modules/Sql.pmod/pgsql.pike:1813:    else {    paramValues[pi++]=value;    rval=sprintf("$%d",pi);    }    to[rep++]=rval;    }    if(rep--)    q=replace(q,from=from[..rep],to=to[..rep]);    paramValues= pi ? paramValues[..pi-1] : ({});    from=({from,to,paramValues}); +  }    } else -  paramValues = ({}); +  paramValues=({});    if(String.width(q)>8)    ERROR("Wide string literals in %O not supported\n",q);    if(has_value(q,"\0"))    ERROR("Querystring %O contains invalid literal nul-characters\n",q);    mapping(string:mixed) tp;    if(waitforauthready) {    Thread.MutexKey lock=waitforauth->lock();    catch(waitforauthready->wait(lock));    lock=0;    }    int tstart; -  if(forcetext) { -  if(bindings) -  q = .sql_util.emulate_bindings(q, bindings, this); -  } else if(forcecache==1 +  if(!forcetext && forcecache==1    || forcecache!=0    && (sizeof(q)>=MINPREPARELENGTH || .pgsql_util.cachealways[q])) {    object plugbuffer=c->start();    if(tp=_prepareds[q]) {    if(tp.preparedname) {   #ifdef PG_STATS    prepstmtused++;   #endif    preparedname=tp.preparedname;    } else if((tstart=tp.trun)
pike.git/lib/modules/Sql.pmod/pgsql.pike:1855:    if(totalhits>=cachedepth)    foreach(_prepareds;string ind;tp) {    int oldhits=tp.hits;    totalhits-=oldhits-(tp.hits=oldhits>>1);    if(oldhits<=1) {    closestatement(plugbuffer,tp.preparedname);    m_delete(_prepareds,ind);    }    }    if(forcecache!=1 && .pgsql_util.createprefix->match(q)) { -  invalidatecache=1; // Flush cache on CREATE +  invalidatecache=1; // Flush cache on CREATE    tp=UNDEFINED;    } else    _prepareds[q]=tp=([]);    }    if(invalidatecache) {    invalidatecache=0;    foreach(_prepareds;;mapping np) {    closestatement(plugbuffer,np.preparedname);    m_delete(np,"preparedname");    }
pike.git/lib/modules/Sql.pmod/pgsql.pike:1883:    } else // pgsql_result autoassigns to portal    tp=UNDEFINED;    object portal;    portal=.pgsql_util.pgsql_result(this,c,q,    portalbuffersize,_alltyped,from,forcetext);    portal._tprepared=tp;   #ifdef PG_STATS    portalsopened++;   #endif    clearmessage=1; -  object plugbuffer=c; +     if(forcetext) { // FIXME What happens if portals are still open?    portal._unnamedportalkey=_unnamedportalmux->lock(1); -  +  portal._portalname="";    portal->_openportal();    _readyforquerycount++;    Thread.MutexKey lock=unnamedstatement->lock(1); -  plugbuffer->start(1)->add_int8('Q')->add_hstring(q,4,4+1)->add_int8(0) +  c->start(1)->add_int8('Q')->add_hstring(q,4,4+1)->add_int8(0)    ->sendcmd(flushlogsend,portal);    lock=0;    PD("Simple query: %O\n",q);    } else { -  object parsebuffer; +  object plugbuffer;    if(!sizeof(preparedname) || !tp || !tp.preparedname) {    if(!sizeof(preparedname))    preparedname=    (portal._unnamedstatementkey=unnamedstatement->trylock(1))    ? "" : PTSTMTPREFIX+int2hex(ptstmtcount++);    // Even though the protocol doesn't require the Parse command to be    // followed by a flush, it makes a VERY noticeable difference in    // performance if it is omitted; seems like a flaw in the PostgreSQL    // server v8.3.3    PD("Parse statement %O=%O\n",preparedname,q); -  parsebuffer=plugbuffer->start()->add_int8('P') +  plugbuffer=c->start()->add_int8('P')    ->add_hstring(({preparedname,0,q,"\0\0\0"}),4,4)->add(PGFLUSH);    }    if(!tp || !tp.datatypeoid) {    PD("Describe statement %O\n",preparedname); -  (parsebuffer||plugbuffer->start())->add_int8('D') +  (plugbuffer||c->start())->add_int8('D')    ->add_hstring(({'S',preparedname,0}),4,4)->sendcmd(flushsend,portal);    } else { -  if(parsebuffer) -  parsebuffer->sendcmd(); +  if(plugbuffer) +  plugbuffer->sendcmd();   #ifdef PG_STATS    skippeddescribe++;   #endif    portal->_setrowdesc(tp.datarowdesc);    }    portal._preparedname=preparedname;    if((portal._tprepared=tp) && tp.datatypeoid) {    mixed e=catch(portal->_preparebind(tp.datatypeoid)); -  if(e && !portal._delayederror) { -  if(!stringp(e)) +  if(e && !portal._delayederror)    throw(e); -  portal._delayederror=e; +     }    } -  } +     throwdelayederror(portal);    return portal;   }      //! This is an alias for @[big_query()], since @[big_query()] already supports   //! streaming of multiple simultaneous queries through the same connection.   //!   //! @seealso   //! @[big_query()], @[big_typed_query()], @[Sql.Sql], @[Sql.sql_result]   object streaming_query(string q,void|mapping(string|int:mixed) bindings) {