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

version» Context lines:

pike.git/lib/modules/Sql.pmod/pgsql.pike:448:    return replace(glob, ({"*", "?", "\\", "%", "_"}),    ({"%", "_", "\\\\", "\\%", "\\_"}));   }      private void waitauthready() {    if (proxy.waitforauthready) {    PD("%d Wait for auth ready %O\n",    proxy.c?->socket && proxy.c->socket->query_fd(), backtrace()[-2]);    Thread.MutexKey lock = proxy.shortmux->lock();    catch(PT(proxy.waitforauthready->wait(lock))); -  lock = 0; +     PD("%d Wait for auth ready released.\n",    proxy.c?->socket && proxy.c->socket->query_fd());    }   }      //! Closes the connection to the database, any running queries are   //! terminated instantly.   //!   //! @note   //! This function is PostgreSQL-specific.
pike.git/lib/modules/Sql.pmod/pgsql.pike:875:   }      private inline string int2hex(int i) {    return String.int2hex(i);   }      private inline void throwdelayederror(object parent) {    .pgsql_util.throwdelayederror(parent);   }    + private void startquery(int forcetext, .pgsql_util.Result portal, string q, +  mapping(string:mixed) tp, string preparedname) { +  .pgsql_util.conxion c = proxy.c; +  if (forcetext) { // FIXME What happens if portals are still open? +  portal._unnamedportalkey = proxy.unnamedportalmux->lock(1); +  portal._portalname = ""; +  portal->_parseportal(); portal->_bindportal(); +  proxy.readyforquerycount++; +  { +  Thread.MutexKey lock = proxy.unnamedstatement->lock(1); +  .pgsql_util.conxsess cs = c->start(1); +  CHAIN(cs)->add_int8('Q')->add_hstring(({q, 0}), 4, 4); +  cs->sendcmd(FLUSHLOGSEND, portal); +  } +  PD("Simple query: %O\n", q); +  } else { +  object plugbuffer; +  portal->_parseportal(); +  if (!sizeof(preparedname) || !tp || !tp.preparedname) { +  if (!sizeof(preparedname)) +  preparedname = +  (portal._unnamedstatementkey = proxy.unnamedstatement->trylock(1)) +  ? "" : PTSTMTPREFIX + int2hex(ptstmtcount++); +  PD("Parse statement %O=%O\n", preparedname, q); +  plugbuffer = c->start(); +  CHAIN(plugbuffer)->add_int8('P') +  ->add_hstring(({preparedname, 0, q, "\0\0\0"}), 4, 4) + #if 0 +  // 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 +  // In v8.4 and later, things speed up slightly when it is omitted. +  ->add(PGFLUSH) + #endif +  ; +  } else { // Use the name from the cache +  preparedname = tp.preparedname; // to shortcut a potential race +  PD("Using prepared statement %s for %O\n", preparedname, q); +  } +  portal._preparedname = preparedname; +  if (!tp || !tp.datatypeoid) { +  PD("Describe statement %O\n", preparedname); +  if (!plugbuffer) +  plugbuffer = c->start(); +  CHAIN(plugbuffer)->add_int8('D') +  ->add_hstring(({'S', preparedname, 0}), 4, 4); +  plugbuffer->sendcmd(FLUSHSEND, portal); +  } else { +  if (plugbuffer) +  plugbuffer->sendcmd(KEEP); + #ifdef PG_STATS +  skippeddescribe++; + #endif +  portal->_setrowdesc(tp.datarowdesc, tp.datarowtypes); +  } +  if ((portal._tprepared=tp) && tp.datatypeoid) { +  mixed e = catch(portal->_preparebind(tp.datatypeoid)); +  if (e && !portal.delayederror) { +  portal._unnamedstatementkey = 0; // Release early, release often +  throw(e); +  } +  } +  if (!proxy.unnamedstatement) +  portal._unnamedstatementkey = 0; // Cover for a destruct race +  } + } +    //! This is the only provided direct interface which allows you to query the   //! database. A simpler synchronous interface can be used through @[query()].   //!   //! Bindings are supported natively straight across the network.   //! Special bindings supported are:   //! @mapping   //! @member int ":_cache"   //! Forces caching on or off for the query at hand.   //! @member int ":_text"   //! Forces text mode in communication with the database for queries on or off
pike.git/lib/modules/Sql.pmod/pgsql.pike:899:   //! @member int ":_sync"   //! Forces synchronous parsing on or off for statements.   //! Setting this to off can cause surprises because statements could   //! be parsed before the previous statements have been executed   //! (e.g. references to temporary tables created in the preceding   //! statement),   //! but it can speed up parsing due to increased parallelism.   //! @endmapping   //!   //! @note - //! The bindings-parameter passed to this function must remain unaltered + //! The parameters referenced via the @expr{bindings@}-parameter-mapping + //! passed to this function must remain unaltered   //! until the parameters have been sent to the database. The driver   //! currently does not expose this moment, but to avoid a race condition   //! it is sufficient to keep them unaltered until the first resultrow   //! has been fetched (or EOF is reached, in case of no resultrows).   //!   //! @returns   //! A @[Sql.pgsql_util.Result] object (which conforms to the   //! @[Sql.Result] standard interface for accessing data). It is   //! recommended to use @[query()] for simpler queries (because   //! it is easier to handle, but stores all the result in memory), and
pike.git/lib/modules/Sql.pmod/pgsql.pike:1008:    paramValues = pi ? paramValues[..pi-1] : .pgsql_util.emptyarray;    from = ({from, to, paramValues});    }    } else    paramValues = .pgsql_util.emptyarray;    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; -  int tstart; +     /*    * FIXME What happens with regards to this detection when presented with    * multistatement text-queries?    * The primary function of this detection is to ensure a SYNC    * right after a COMMIT, and no SYNC after a BEGIN.    */    int transtype = .pgsql_util.transendprefix->match(q) ? TRANSEND    : .pgsql_util.transbeginprefix->match(q) ? TRANSBEGIN : NOTRANS;    if (transtype != NOTRANS)    tp = .pgsql_util.describenodata; // Description already known    else if (!forcetext && forcecache == 1    || forcecache && sizeof(q) >= MINPREPARELENGTH) {    object plugbuffer = c->start();    if (tp = proxy.prepareds[q]) {    if (tp.preparedname) {   #ifdef PG_STATS    prepstmtused++;   #endif    preparedname = tp.preparedname; -  } else if((tstart = tp.trun) -  && tp.tparse*FACTORPLAN >= tstart +  } else if(tp.trun && tp.tparse*FACTORPLAN >= tp.trun    && (undefinedp(options.cache_autoprepared_statements)    || options.cache_autoprepared_statements))    preparedname = PREPSTMTPREFIX + int2hex(pstmtcount++);    } else {    if (proxy.totalhits >= cachedepth)    foreach (proxy.prepareds; string ind; tp) {    int oldhits = tp.hits;    proxy.totalhits -= oldhits-(tp.hits = oldhits >> 1);    if (oldhits <= 1) {    closestatement(plugbuffer, tp.preparedname);
pike.git/lib/modules/Sql.pmod/pgsql.pike:1058:    proxy.prepareds[q] = tp = ([]);    }    if (proxy.invalidatecache) {    proxy.invalidatecache = 0;    foreach (proxy.prepareds; ; mapping np) {    closestatement(plugbuffer, np.preparedname);    m_delete(np, "preparedname");    }    }    if (sizeof(CHAIN(plugbuffer))) { -  PD("%O\n",(string)CHAIN(plugbuffer)); +  PD("%O\n", (string)CHAIN(plugbuffer));    plugbuffer->sendcmd(FLUSHSEND); // close expireds    } else    plugbuffer->sendcmd(KEEP); // close start() -  tstart = gethrtime(); +     } else // Result autoassigns to portal    tp = 0;    .pgsql_util.Result portal;    portal = .pgsql_util.Result(proxy, c, q, portalbuffersize, _alltyped,    from, forcetext, timeout, syncparse, transtype);    portal._tprepared = tp;   #ifdef PG_STATS    portalsopened++;   #endif    proxy.clearmessage = 1; -  if (forcetext) { // FIXME What happens if portals are still open? -  portal._unnamedportalkey = proxy.unnamedportalmux->lock(1); -  portal._portalname = ""; -  portal->_parseportal(); portal->_bindportal(); -  proxy.readyforquerycount++; -  Thread.MutexKey lock = proxy.unnamedstatement->lock(1); -  .pgsql_util.conxsess cs = c->start(1); -  CHAIN(cs)->add_int8('Q')->add_hstring(({q, 0}), 4, 4); -  cs->sendcmd(FLUSHLOGSEND, portal); -  lock = 0; -  PD("Simple query: %O\n", q); -  } else { -  object plugbuffer; -  portal->_parseportal(); -  if (!sizeof(preparedname) || !tp || !tp.preparedname) { -  if (!sizeof(preparedname)) -  preparedname= -  (portal._unnamedstatementkey = proxy.unnamedstatement->trylock(1)) -  ? "" : PTSTMTPREFIX+int2hex(ptstmtcount++); -  PD("Parse statement %O=%O\n", preparedname, q); -  plugbuffer = c->start(); -  CHAIN(plugbuffer)->add_int8('P') -  ->add_hstring(({preparedname, 0, q, "\0\0\0"}), 4, 4) - #if 0 -  // 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 -  // In v8.4 and later, things speed up slightly when it is omitted. -  ->add(PGFLUSH) - #endif -  ; -  } else { // Use the name from the cache -  preparedname = tp.preparedname; // to shortcut a potential race -  PD("Using prepared statement %s for %O\n", preparedname, q); -  } -  portal._preparedname = preparedname; -  if (!tp || !tp.datatypeoid) { -  PD("Describe statement %O\n", preparedname); -  if (!plugbuffer) -  plugbuffer = c->start(); -  CHAIN(plugbuffer)->add_int8('D') -  ->add_hstring(({'S', preparedname, 0}), 4, 4); -  plugbuffer->sendcmd(FLUSHSEND, portal); -  } else { -  if (plugbuffer) -  plugbuffer->sendcmd(KEEP); - #ifdef PG_STATS -  skippeddescribe++; - #endif -  portal->_setrowdesc(tp.datarowdesc, tp.datarowtypes); -  } -  if ((portal._tprepared=tp) && tp.datatypeoid) { -  mixed e = catch(portal->_preparebind(tp.datatypeoid)); -  if (e && !portal.delayederror) { -  portal._unnamedstatementkey = 0; // Release early, release often -  throw(e); -  } -  } -  if (!proxy.unnamedstatement) -  portal._unnamedstatementkey = 0; // Cover for a destruct race -  } +  // Do not run a query in the local_backend to prevent deadlocks +  if (Thread.this_thread() == .pgsql_util.local_backend.executing_thread()) +  Thread.Thread(startquery, forcetext, portal, q, tp, preparedname); +  else +  startquery(forcetext, portal, q, tp, preparedname);    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.Connection], @[Sql.Result]   /*semi*/final variant inline .pgsql_util.Result streaming_query(string q,