pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:29:
#define PURGED 7
// If this is extended, change the type of _state
#define NOERROR 0 // Error states networkparser
#define PROTOCOLERROR 1
#define PROTOCOLUNSUPPORTED 2
#define LOSTERROR "Database connection lost"
//! The instance of the pgsql dedicated backend.
- final Pike.Backend local_backend = Pike.SmallBackend();
+ final Pike.Backend local_backend;
-
+ private Pike.Backend cb_backend;
private Thread.Mutex backendmux = Thread.Mutex();
private Thread.ResourceCount clientsregistered = Thread.ResourceCount();
constant emptyarray = ({});
constant describenodata
= (["datarowdesc":emptyarray, "datarowtypes":emptyarray,
"datatypeoid":emptyarray]);
private constant censoroptions = (<"use_ssl", "force_ssl",
"cache_autoprepared_statements", "reconnect", "text_query", "is_superuser",
"server_encoding", "server_version", "integer_datetimes",
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:90:
* not be able to deliver results belonging to other parallel queries
* running on the same filedescriptor.
*
* However, considering that the current heuristic increases query-speed
* in the majority of the real-world cases, it would be considered a good
* tradeoff.
*/
private Regexp execfetchlimit
= iregexp("^\a*((UPDA|DELE)TE|INSERT)\a|\aLIMIT\a+[1-9][; \t\f\r\n]*$");
+ private void default_backend_runs() { // Runs as soon as the
+ cb_backend = Pike.DefaultBackend; // DefaultBackend has started
+ }
+
+ private void create() {
+ // Run callbacks from our local_backend until DefaultBackend has started
+ cb_backend = local_backend = Pike.SmallBackend();
+ call_out(default_backend_runs, 0);
+ }
+
private Regexp iregexp(string expr) {
Stdio.Buffer ret = Stdio.Buffer();
foreach (expr; ; int c)
if (c >= 'A' && c <= 'Z')
ret->add('[', c, c + 'a' - 'A', ']');
else if (c == '\a') // Replace with generic whitespace
ret->add("[ \t\f\r\n]");
else
ret->add_int8(c);
return Regexp(ret->read());
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:120:
Thread.MutexKey lock;
int looponce;
do {
looponce = 0;
if (lock = backendmux->trylock()) {
PD("Starting local backend\n");
while (!clientsregistered->drained() // Autoterminate when not needed
|| sizeof(local_backend->call_out_info())) {
mixed err;
if (err = catch(local_backend(4096.0)))
- werror(describe_backtrace(err));
+ master()->handle_error(err);
}
PD("Terminating local backend\n");
lock = 0;
looponce = !clientsregistered->drained();
}
} while (looponce);
}
//! Registers yourself as a user of this backend. If the backend
//! has not been started yet, it will be spawned automatically.
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:152:
parent->untolderror = 0;
else if (parent->pgsqlsess)
parent->pgsqlsess->untolderror = 0;
parent.delayederror = 0;
if (stringp(err))
err = ({err, backtrace()[..<2]});
throw(err);
}
}
- private int oidformat(int oid) {
+ private int readoidformat(int oid) {
switch (oid) {
case BOOLOID:
case BYTEAOID:
case CHAROID:
case INT8OID:
case INT2OID:
case INT4OID:
-
+ case FLOAT4OID:
+ #if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
+ case FLOAT8OID:
+ #endif
case TEXTOID:
case OIDOID:
case XMLOID:
-
+ case DATEOID:
+ case TIMEOID:
+ case TIMETZOID:
+ case TIMESTAMPOID:
+ case TIMESTAMPTZOID:
+ case INTERVALOID:
+ case INT4RANGEOID:
+ case INT8RANGEOID:
+ case DATERANGEOID:
+ case TSRANGEOID:
+ case TSTZRANGEOID:
case MACADDROID:
case BPCHAROID:
case VARCHAROID:
-
+ case CIDROID:
+ case INETOID:
case CTIDOID:
case UUIDOID:
return 1; //binary
}
return 0; // text
}
-
+ private int writeoidformat(int oid, array(string|int) paramValues,
+ array(int) ai) {
+ mixed value = paramValues[ai[0]++];
+ switch (oid) {
+ case BOOLOID:
+ case BYTEAOID:
+ case CHAROID:
+ case INT8OID:
+ case INT2OID:
+ case INT4OID:
+ case TEXTOID:
+ case OIDOID:
+ case XMLOID:
+ case MACADDROID:
+ case BPCHAROID:
+ case VARCHAROID:
+ case CTIDOID:
+ case UUIDOID:
+ return 1; //binary
+ case CIDROID:
+ case INETOID:
+ case DATEOID:
+ case TIMEOID:
+ case TIMETZOID:
+ case TIMESTAMPOID:
+ case TIMESTAMPTZOID:
+ case INTERVALOID:
+ case INT4RANGEOID:
+ case INT8RANGEOID:
+ case DATERANGEOID:
+ case TSRANGEOID:
+ case TSTZRANGEOID:
+ case FLOAT4OID:
+ #if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
+ case FLOAT8OID:
+ #endif
+ if (!stringp(value))
+ return 1;
+ }
+ return 0; // text
+ }
+
+ #define DAYSEPOCHTO2000 10957 // 2000/01/01 00:00:00 UTC
+ #define USEPOCHTO2000 (DAYSEPOCHTO2000*24*3600*1000000)
+
+ private array timestamptotype
+ = ({Val.Timestamp, 8, USEPOCHTO2000, "usecs", 8});
+ private array datetotype = ({Val.Date, 4, DAYSEPOCHTO2000, "days", 4});
+
+ private mapping(int:array) oidtotype = ([
+ DATEOID: datetotype,
+ TIMEOID: ({Val.Time, 8, 0, "usecs", 8}),
+ TIMETZOID: ({Val.TimeTZ, 12, 0, "usecs", 8, "timezone", 4}),
+ INTERVALOID: ({Val.Interval, 16, 0, "usecs", 8, "days", 4, "months",4}),
+ TIMESTAMPOID: timestamptotype,
+ TIMESTAMPTZOID: timestamptotype,
+ INT4RANGEOID: ({0, 4}),
+ INT8RANGEOID: ({0, 8}),
+ DATERANGEOID: datetotype,
+ TSRANGEOID: timestamptotype,
+ TSTZRANGEOID: timestamptotype,
+ ]);
+
private inline mixed callout(function(mixed ...:void) f,
float|int delay, mixed ... args) {
- return local_backend->call_out(f, delay, @args);
+ return cb_backend->call_out(f, delay, @args);
}
// Some pgsql utility functions
class bufcon {
inherit Stdio.Buffer;
private Thread.ResourceCountKey dirty;
#ifdef PG_DEBUGRACE
final bufcon `chain() {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:258: Inside #if defined(PG_DEBUG)
protected final bool range_error(int howmuch) {
#ifdef PG_DEBUG
if (howmuch <= 0)
error("Out of range %d\n", howmuch);
#endif
if (fillread) {
Thread.MutexKey lock = fillreadmux->lock();
if (!didreadcb)
fillread.wait(lock);
didreadcb = 0;
- lock = 0;
+
} else
throw(MAGICTERMINATE);
return true;
}
final int read_cb(mixed id, mixed b) {
PD("Read callback %O\n", b && ((string)b)
#ifndef PG_DEBUGMORE
[..255]
#endif
);
Thread.MutexKey lock = fillreadmux->lock();
if (procmsg && id)
procmsg = 0, lock = 0, Thread.Thread(id);
else if (fillread)
didreadcb = 1, fillread.signal();
- lock = 0;
+
return 0;
}
private void create() {
i::create();
fillreadmux = Thread.Mutex();
fillread = Thread.Condition();
}
};
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:432:
PD("Flush\n");
add(PGFLUSH);
case SENDOUT:;
}
if (towrite = sizeof(this)) {
PD("%d>Sendcmd %O\n",
socket->query_fd(), ((string)this)[..towrite-1]);
towrite -= output_to(socket, towrite);
}
} while (0);
- lock = started = 0;
+ started = 0;
return;
};
lock = 0;
PD("Sendcmd failed %s\n", describe_backtrace(err));
destruct(this);
}
final int close() {
if (!closenext && nostash) {
closenext = 1;
-
+ {
Thread.MutexKey lock = i->fillreadmux->lock();
- if (i->fillread) { // Delayed close() after flushing the output buffer
+ if (i->fillread) { // Delayed close() after flushing the output buffer
i->fillread.signal();
i->fillread = 0;
}
- lock = 0;
+ }
PD("%d>Delayed close, flush write\n", socket->query_fd());
i->read_cb(socket->query_id(), 0);
return 0;
} else
return -1;
}
final void purge() {
if (stashcount) {
stashcount = 0;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:677:
|| (_unnamedstatementkey ? "*parsing*" : ""));
break;
}
return res;
}
protected void create(proxy _pgsqlsess, conxion _c, string query,
int _portalbuffersize, int alltyped, array params, int forcetext,
int _timeout, int _syncparse, int _transtype) {
pgsqlsess = _pgsqlsess;
- if (catch(cr = (c = _c)->i))
+ if (c = _c)
+ cr = c->i;
+ else
losterror();
_query = query;
datarows = Thread.Queue();
_ddescribe = Thread.Condition();
_ddescribemux = Thread.Mutex();
closemux = Thread.Mutex();
portalbuffersize = _portalbuffersize;
alltext = !alltyped;
_params = params;
_forcetext = forcetext;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:724:
final void _storetiming() {
if (_tprepared) {
_tprepared.trun = gethrtime() - _tprepared.trunstart;
m_delete(_tprepared, "trunstart");
_tprepared = 0;
}
}
private void waitfordescribe() {
+ {
Thread.MutexKey lock = _ddescribemux->lock();
if (!datarowtypes)
PT(_ddescribe->wait(lock));
- lock = 0;
+ }
if (this) // If object already destructed, skip the next call
trydelayederror(); // since you cannot call functions anymore
else
error(LOSTERROR);
}
//! @seealso
//! @[Sql.Result()->num_fields()]
/*semi*/final int num_fields() {
if (!datarowtypes)
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:809:
#endif
foreach (datarowtypes; int i; int typ) {
int collen = cr->read_sint(4);
if (collen > 0) {
#ifdef PG_DEBUG
msglen -= collen;
#endif
mixed value;
switch (typ) {
case FLOAT4OID:
- #if SIZEOF_FLOAT>=8
+ #if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
case FLOAT8OID:
#endif
-
+ if (_forcetext) {
if (!alltext) {
value = (float)cr->read(collen);
break;
}
-
+ } else {
+ [ value ] = cr->sscanf(collen == 4 ? "%4F" : "%8F");
+ if (alltext)
+ value = (string)value;
+ break;
+ }
default:value = cr->read(collen);
break;
case CHAROID:
value = alltext ? cr->read(1) : cr->read_int8();
break;
case BOOLOID:value = cr->read_int8();
switch (value) {
case 'f':value = 0;
break;
case 't':value = 1;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:839:
break;
case TEXTOID:
case BPCHAROID:
case VARCHAROID:
value = cr->read(collen);
if (cenc == UTF8CHARSET && catch(value = utf8_to_string(value))
&& !serror)
serror = SERROR("%O contains non-%s characters\n",
value, UTF8CHARSET);
break;
+ case INT4RANGEOID:
+ case INT8RANGEOID:
+ case DATERANGEOID:
+ case TSRANGEOID:
+ case TSTZRANGEOID:
+ if (_forcetext)
+ value = cr->read(collen);
+ else {
+ array totype = oidtotype[typ];
+ mixed from = -Math.inf, till = Math.inf;
+ switch (cr->read_int8()) {
+ case 1: from = till = 0;
+ break;
+ case 0x12: from = cr->read_sint(cr->read_int32());
+ break;
+ case 2: from = cr->read_sint(cr->read_int32());
+ case 8: till = cr->read_sint(cr->read_int32());
+ }
+ if (totype[0]) {
+ if (intp(from)) {
+ value = totype[0]();
+ value[totype[3]] = from + totype[2];
+ from = value;
+ }
+ if (intp(till)) {
+ value = totype[0]();
+ value[totype[3]] = till + totype[2];
+ till = value;
+ }
+ }
+ value = Val.Range(from, till);
+ if (alltext)
+ value = value->sql();
+ }
+ break;
+ case CIDROID:
+ case INETOID:
+ if (_forcetext)
+ value = cr->read(collen);
+ else {
+ value = Val.Inet();
+ int iptype = cr->read_int8(); // 2 == IPv4, 3 == IPv6
+ value->masklen = cr->read_int8() + (iptype == 2 && 12*8);
+ cr->read_int8(); // 0 == INET, 1 == CIDR
+ value->address = cr->read_hint(1);
+ if (alltext)
+ value = (string)value;
+ }
+ break;
+ case TIMESTAMPOID:
+ case TIMESTAMPTZOID:
+ case INTERVALOID:
+ case TIMETZOID:
+ case TIMEOID:
+ case DATEOID:
+ if (_forcetext)
+ value = cr->read(collen);
+ else {
+ array totype = oidtotype[typ];
+ value = totype[0]();
+ value[totype[3]] = cr->read_sint(totype[4]) + totype[2];
+ int i = 5;
+ while (i < sizeof(totype)) {
+ value[totype[i]] = cr->read_sint(totype[i+1]);
+ i += 2;
+ }
+ if (alltext)
+ value = (string)value;
+ }
+ break;
case INT8OID:case INT2OID:
case OIDOID:case INT4OID:
if (_forcetext) {
value = cr->read(collen);
if (!alltext)
value = (int)value;
} else {
switch (typ) {
case INT8OID:value = cr->read_sint(8);
break;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:876:
return msglen;
#endif
}
final void _setrowdesc(array(mapping(string:mixed)) drowdesc,
array(int) drowtypes) {
Thread.MutexKey lock = _ddescribemux->lock();
datarowdesc = drowdesc;
datarowtypes = drowtypes;
_ddescribe->broadcast();
- lock = 0;
+
}
final void _preparebind(array dtoid) {
array(string|int) paramValues =_params ? _params[2] : emptyarray;
if (sizeof(dtoid) != sizeof(paramValues))
SUSERERROR("Invalid number of bindings, expected %d, got %d\n",
sizeof(dtoid), sizeof(paramValues));
Thread.MutexKey lock = _ddescribemux->lock();
if (!_portalname) {
_portalname
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:900:
+ (string)(c->socket->query_fd()) + "_"
#endif
+ String.int2hex(pgsqlsess.pportalcount++);
lock = 0;
#ifdef PG_DEBUGMORE
PD("ParamValues to bind: %O\n", paramValues);
#endif
Stdio.Buffer plugbuffer = Stdio.Buffer();
{ array dta = ({sizeof(dtoid)});
plugbuffer->add(_portalname, 0, _preparedname, 0)
- ->add_ints(dta + map(dtoid, oidformat) + dta, 2);
+ ->add_ints(dta
+ + map(dtoid, writeoidformat, paramValues, ({0})) + dta, 2);
}
string cenc = pgsqlsess.runtimeparameter[CLIENT_ENCODING];
foreach (paramValues; int i; mixed value) {
if (undefinedp(value) || objectp(value) && value->is_val_null)
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
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:999:
};
break;
default:
value = 1;
break;
case 0:case '0':case 'f':case 'F':case 'n':case 'N':
value = 0;
break;
}
} while (0);
- plugbuffer->add_int32(1)->add_int8(value);
+ plugbuffer->add("\0\0\0\1", value);
break;
case CHAROID:
if (intp(value))
plugbuffer->add_hstring(value, 4);
else {
value = (string)value;
switch (sizeof(value)) {
default:
SUSERERROR(
"\"char\" types must be 1 byte wide, got %O\n", value);
case 0:
plugbuffer->add_int32(-1); // NULL
break;
case 1:
plugbuffer->add_hstring(value[0], 4);
}
}
break;
-
+ case INT4RANGEOID:
+ case INT8RANGEOID:
+ case DATERANGEOID:
+ case TSRANGEOID:
+ case TSTZRANGEOID:
+ if (stringp(value))
+ plugbuffer->add_hstring(value, 4);
+ else if (value->from >= value->till)
+ plugbuffer->add("\0\0\0\1\1");
+ else {
+ array totype = oidtotype[dtoid[i]];
+ int w = totype[1];
+ int from, till;
+ if (totype[0])
+ from = value->from, till = value->till;
+ else {
+ from = value->from[totype[3]] - totype[2];
+ till = value->till[totype[3]] - totype[2];
+ }
+ if (value->till == Math.inf)
+ if (value->from == -Math.inf)
+ plugbuffer->add("\0\0\0\1\30");
+ else
+ plugbuffer->add("\0\0\0", 1 + 4 + w, "\22\0\0\0", w)
+ ->add_int(from, w);
+ else {
+ if (value->from == -Math.inf)
+ plugbuffer->add("\0\0\0", 1 + 4 + w, 8);
+ else
+ plugbuffer->add("\0\0\0", 1 + 4 * 2 + w * 2, "\2\0\0\0", w)
+ ->add_int(from, w);
+ plugbuffer->add_int32(w)->add_int(till, w);
+ }
+ }
+ break;
+ case CIDROID:
+ case INETOID:
+ if (stringp(value))
+ plugbuffer->add_hstring(value, 4);
+ else if (value->address <= 0xffffffff) // IPv4
+ plugbuffer->add("\0\0\0\10\2",
+ value->masklen - 12 * 8, dtoid[i] == CIDROID, 4)
+ ->add_int32(value->address);
+ else // IPv6
+ plugbuffer->add("\0\0\0\24\3",
+ value->masklen, dtoid[i] == CIDROID, 16)
+ ->add_int(value->address, 16);
+ break;
+ case DATEOID:
+ case TIMEOID:
+ case TIMETZOID:
+ case INTERVALOID:
+ case TIMESTAMPOID:
+ case TIMESTAMPTZOID:
+ if (stringp(value))
+ plugbuffer->add_hstring(value, 4);
+ else {
+ array totype = oidtotype[dtoid[i]];
+ if (!objectp(value))
+ value = totype[0](value);
+ plugbuffer->add_int32(totype[1])
+ ->add_int(value[totype[3]] - totype[2], totype[4]);
+ int i = 5;
+ while (i < sizeof(totype)) {
+ plugbuffer->add_int(value[totype[i]], totype[i+1]);
+ i += 2;
+ }
+ }
+ break;
+ case FLOAT4OID:
+ #if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
+ case FLOAT8OID:
+ #endif
+ if (stringp(value))
+ plugbuffer->add_hstring(value, 4);
+ else {
+ int w = dtoid[i] == FLOAT4OID ? 4 : 8;
+ plugbuffer->add_int32(w)
+ ->sprintf(w == 4 ? "%4F" : "%8F", value);
+ }
+ break;
case INT8OID:
plugbuffer->add_int32(8)->add_int((int)value, 8);
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;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1040:
if (!datarowtypes) {
if (_tprepared && dontcacheprefix->match(_query))
m_delete(pgsqlsess->prepareds, _query), _tprepared = 0;
waitfordescribe();
}
if (_state >= CLOSING)
lock = _unnamedstatementkey = 0;
else {
plugbuffer->add_int16(sizeof(datarowtypes));
if (sizeof(datarowtypes))
- plugbuffer->add_ints(map(datarowtypes, oidformat), 2);
+ plugbuffer->add_ints(map(datarowtypes, readoidformat), 2);
else if (syncparse < 0 && !pgsqlsess->wasparallelisable
&& !pgsqlsess->statementsinflight->drained(1)) {
lock = pgsqlsess->shortmux->lock();
PD("Commit waiting for statements to finish\n");
catch(PT(pgsqlsess->statementsinflight->wait_till_drained(lock, 1)));
}
lock = 0;
PD("Bind portal %O statement %O\n", _portalname, _preparedname);
_fetchlimit = pgsqlsess->_fetchlimit;
_bindportal();
conxsess bindbuffer = c->start();
_unnamedstatementkey = 0;
-
+ stmtifkey = 0;
CHAIN(bindbuffer)->add_int8('B')->add_hstring(plugbuffer, 4, 4);
if (!_tprepared && sizeof(_preparedname))
closestatement(CHAIN(bindbuffer), _preparedname);
_sendexecute(_fetchlimit
&& !(transtype != NOTRANS
|| sizeof(_query) >= MINPREPARELENGTH &&
execfetchlimit->match(_query))
&& _fetchlimit, bindbuffer);
}
- } else
- lock = 0;
+
}
-
+ }
final void _processrowdesc(array(mapping(string:mixed)) datarowdesc,
array(int) datarowtypes) {
_setrowdesc(datarowdesc, datarowtypes);
if (_tprepared) {
_tprepared.datarowdesc = datarowdesc;
_tprepared.datarowtypes = datarowtypes;
}
}
final void _parseportal() {
-
+ {
Thread.MutexKey lock = closemux->lock();
_state = PARSING;
-
+ {
Thread.MutexKey lockc = pgsqlsess->shortmux->lock();
if (syncparse || syncparse < 0 && pgsqlsess->wasparallelisable) {
PD("Commit waiting for statements to finish\n");
catch(PT(pgsqlsess->statementsinflight->wait_till_drained(lockc)));
}
stmtifkey = pgsqlsess->statementsinflight->acquire();
- lockc = 0;
- lock = 0;
+ }
+ }
statuscmdcomplete = 0;
pgsqlsess->wasparallelisable = paralleliseprefix->match(_query);
}
final void _releasestatement(void|int nolock) {
Thread.MutexKey lock;
if (!nolock)
lock = closemux->lock();
if (_state <= BOUND) {
_state = COMMITTED;
stmtifkey = 0;
}
- lock = 0;
+
}
final void _bindportal() {
Thread.MutexKey lock = closemux->lock();
_state = BOUND;
portalsifkey = pgsqlsess->portalsinflight->acquire();
- lock = 0;
+
}
final void _purgeportal() {
PD("Purge portal\n");
datarows->write(1); // Signal EOF
-
+ {
Thread.MutexKey lock = closemux->lock();
_fetchlimit = 0; // disables further Executes
switch (_state) {
case COPYINPROGRESS:
case COMMITTED:
case BOUND:
portalsifkey = 0;
}
switch (_state) {
case BOUND:
case PARSING:
stmtifkey = 0;
}
_state = PURGED;
- lock = 0;
+ }
releaseconditions();
}
final int _closeportal(conxsess cs) {
void|bufcon|conxsess plugbuffer = CHAIN(cs);
int retval = KEEP;
PD("%O Try Closeportal %d\n", _portalname, _state);
Thread.MutexKey lock = closemux->lock();
_fetchlimit = 0; // disables further Executes
switch (_state) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1172:
if (plugbuffer->stashcount->drained() && transtype != TRANSBEGIN)
/*
* stashcount 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.
*/
pgsqlsess->readyforquerycount++, retval = SYNCSEND;
pgsqlsess->pportalcount = 0;
}
}
- lock = 0;
+
return retval;
}
final void _processdataready(array datarow, void|int msglen) {
bytesreceived += msglen;
inflight--;
if (_state<CLOSED)
datarows->write(datarow);
if (++index == 1)
PD("<%O _fetchlimit %d=min(%d||1,%d), inflight %d\n", _portalname,
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1195:
if (_fetchlimit) {
_fetchlimit =
min((portalbuffersize >> 1) * index / bytesreceived || 1,
pgsqlsess._fetchlimit);
Thread.MutexKey lock = closemux->lock();
if (_fetchlimit && inflight <= (_fetchlimit - 1) >> 1)
_sendexecute(_fetchlimit);
else if (!_fetchlimit)
PD("<%O _fetchlimit %d, inflight %d, skip execute\n",
_portalname, _fetchlimit, inflight);
- lock = 0;
+
}
}
private void releaseconditions() {
_unnamedportalkey = _unnamedstatementkey = 0;
if (!datarowtypes) {
if (_state != PURGED && !delayederror)
delayederror = LOSTERROR;
datarowtypes = emptyarray;
_ddescribe->broadcast();
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1248:
if (!fetchlimit) {
if (transtype != NOTRANS)
pgsqlsess.intransaction = transtype == TRANSBEGIN;
flushmode = _closeportal(plugbuffer) == SYNCSEND
|| transtype == TRANSEND ? SYNCSEND : FLUSHSEND;
} else
inflight += fetchlimit, flushmode = FLUSHSEND;
plugbuffer->sendcmd(flushmode, this);
}
+ inline private array setuptimeout() {
+ return local_backend->call_out(gottimeout, timeout);
+ }
+
//! @returns
//! One result row at a time.
//!
//! When using COPY FROM STDOUT, this method returns one row at a time
//! as a single string containing the entire row.
//!
//! @seealso
//! @[eof()], @[send_row()]
/*semi*/final array(mixed) fetch_row() {
int|array datarow;
if (arrayp(datarow = datarows->try_read()))
return datarow;
if (!eoffound) {
if (!datarow) {
PD("%O Block for datarow\n", _portalname);
- array cid = callout(gottimeout, timeout);
+ array cid = setuptimeout();
PT(datarow = datarows->read());
local_backend->remove_call_out(cid);
if (arrayp(datarow))
return datarow;
}
eoffound = 1;
datarows->write(1); // Signal EOF for other threads
}
trydelayederror();
return 0;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1289:
//! When using COPY FROM STDOUT, this method returns one row at a time
//! as a single string containing the entire row.
//!
//! @seealso
//! @[eof()], @[fetch_row()]
/*semi*/final array(array(mixed)) fetch_row_array() {
if (eoffound)
return 0;
array(array|int) datarow = datarows->try_read_array();
if (!sizeof(datarow)) {
- array cid = callout(gottimeout, timeout);
+ array cid = setuptimeout();
PT(datarow = datarows->read_array());
local_backend->remove_call_out(cid);
}
if (arrayp(datarow[-1]))
return datarow;
trydelayederror();
eoffound = 1;
datarows->write(1); // Signal EOF for other threads
return (datarow = datarow[..<1]);
}
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1329:
cs->sendcmd(SENDOUT);
} else
_releasesession();
}
private void run_result_cb(
function(Result, array(mixed), mixed ...:void) callback,
array(mixed) args) {
int|array datarow;
for (;;) {
- array cid = callout(gottimeout, timeout);
+ array cid = setuptimeout();
PT(datarow = datarows->read());
local_backend->remove_call_out(cid);
if (!arrayp(datarow))
break;
callout(callback, 0, this, datarow, @args);
}
eoffound = 1;
callout(callback, 0, this, 0, @args);
}
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1358:
mixed ... args) {
if (callback)
Thread.Thread(run_result_cb, callback, args);
}
private void run_result_array_cb(
function(Result, array(array(mixed)), mixed ...:void) callback,
array(mixed) args) {
array(array|int) datarow;
for (;;) {
- array cid = callout(gottimeout, timeout);
+ array cid = setuptimeout();
PT(datarow = datarows->read_array());
local_backend->remove_call_out(cid);
if (!datarow || !arrayp(datarow[-1]))
break;
callout(callback, 0, this, datarow, @args);
}
eoffound = 1;
if (sizeof(datarow)>1)
callout(callback, 0, this, datarow = datarow[..<1], @args);
callout(callback, 0, this, 0, @args);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1421:
final int warningsdropcount; // Number of uncollected warnings
private int warningscollected;
final int(0..1) invalidatecache;
private Thread.Queue qportals;
final mixed delayederror;
private function (:void) readyforquery_cb;
final string host;
final int(0..65535) port;
final string database, user, pass;
- private Crypto.SCRAM SASLcontext;
+ private Crypto.Hash.SCRAM SASLcontext;
final Thread.Condition waitforauthready;
final Thread.Mutex shortmux;
final int readyforquerycount;
private string _sprintf(int type) {
string res;
switch (type) {
case 'O':
res = sprintf(DRIVERNAME".proxy(%s@%s:%d/%s,%d,%d)",
- user, host, port, database, c?->socket && c->socket->query_fd(),
+ user, host, port, database, c && c->socket && c->socket->query_fd(),
backendpid);
break;
}
return res;
}
private void create(void|string host, void|string database,
void|string user, void|string pass,
void|mapping(string:mixed) options) {
if (this::pass = pass) {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1475:
runtimeparameter = ([]);
unnamedportalmux = Thread.Mutex();
unnamedstatement = Thread.Mutex();
readyforquery_cb = connect_cb;
portalsinflight = Thread.ResourceCount();
statementsinflight = Thread.ResourceCount();
wasparallelisable = 0;
}
final int is_open() {
- catch {
- return c->socket->is_open();
- };
- return 0;
+ return c && c->socket && c->socket->is_open();
}
final string geterror(void|int clear) {
throwdelayederror(this);
untolderror = 0;
string s = lastmessage * "\n";
if (clear)
lastmessage = emptyarray;
warningscollected = 0;
return sizeof(s) && s;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1646:
showportalstack("LOOPTOP");
#endif
if (!sizeof(cr)) { // Preliminary check, fast path
Thread.MutexKey lock = cr->fillreadmux->lock();
if (!sizeof(cr)) { // Check for real
if (!cr->fillread) {
lock = 0;
throw(MAGICTERMINATE); // Force proper termination
}
cr->procmsg = 1;
- lock = 0;
+
return; // Terminate thread, wait for callback
}
- lock = 0;
+
}
int msgtype = cr->read_int8();
if (!portal) {
portal = qportals->try_read();
#ifdef PG_DEBUG
showportal(msgtype);
#endif
}
int msglen = cr->read_int32();
msgsreceived++;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:1779:
case "SCRAM-SHA-256":
k = 1;
}
#ifdef PG_DEBUG
msglen -= sizeof(word) + 1;
if (msglen < 1)
break;
#endif
}
if (k) {
- SASLcontext = Crypto.SCRAM(Crypto.SHA256);
+ SASLcontext = Crypto.SHA256.SCRAM();
word = SASLcontext.client_1();
authresponse(({
"SCRAM-SHA-256", 0, sprintf("%4c", sizeof(word)), word
}));
} else
errtype = PROTOCOLUNSUPPORTED;
#ifdef PG_DEBUG
if (msglen != 1)
errtype = PROTOCOLERROR;
msglen = 0;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:2284:
PD("Terminating processloop due to %s\n", describe_backtrace(err));
delayederror = err;
}
destruct(waitforauthready);
c->purge();
};
}
final void close() {
throwdelayederror(this);
+ {
Thread.MutexKey lock;
if (qportals && qportals->size())
catch(cancelquery());
if (unnamedstatement)
termlock = unnamedstatement->lock(1);
if (c) // Prevent trivial backtraces
c->close();
if (unnamedstatement)
lock = unnamedstatement->lock(1);
if (c)
c->purge();
- lock = 0;
+ }
destruct(waitforauthready);
}
private void _destruct() {
string errstring;
mixed err = catch(close());
backendreg = 0;
if (untolderror) {
/*
* Flush out any asynchronously reported errors to stderr; because we are