pike.git
/
lib
/
modules
/
Sql.pmod
/
pgsql_util.pmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:403:
} //! 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 sql_result { private object pgsqlsess;
-
private int numrows;
+
private int eoffound; private conxion c; final mixed _delayederror; final int _state; final int _fetchlimit; final int _alltext; final int _forcetext; final string _portalname;
-
+
private int rowsreceived;
+
private int inflight;
+
private int portalbuffersize;
+
private Stdio.Buffer prepbuffer;
+
private Thread.Condition prepbufferready;
+
private Thread.Mutex prepbuffermux;
+
private Thread.Mutex closemux;
+
private Thread.Queue datarows;
+
private string statuscmdcomplete;
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;
-
private Thread.Mutex closemux;
+
final array _params;
-
final string _statuscmdcomplete;
+
final string _query;
-
final Thread.Queue _datarows;
+
final array(mapping(string:mixed)) _datarowdesc;
-
final int _oldpbpos;
-
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("sql_result numrows: %d
eof: %d inflight: %d\n"
+
res=sprintf("sql_result
state:
%d
numrows: %d eof: %d inflight: %d\n"
"query: %O\n" "portalname: %O datarows: %d" " laststatus: %s\n",
-
numrows
,eoffound,
_
inflight,
+
_state
,
rowsreceived,
eoffound,inflight,
_query, _portalname,_datarowdesc&&sizeof(_datarowdesc),
-
_
statuscmdcomplete||"");
+
statuscmdcomplete||
(_unnamedstatementkey?
"
*parsing*
"
:""
)
)
;
break; } return res; } protected void create(object _pgsqlsess,conxion _c,string query,
-
int portalbuffersize,int alltyped,array params,int forcetext) {
+
int
_
portalbuffersize,int alltyped,array params,int forcetext) {
pgsqlsess = _pgsqlsess; c = _c; _query = query;
-
_
datarows = Thread.Queue();
numrows = UNDEFINED;
+
datarows = Thread.Queue();
_ddescribe=Thread.Condition(); _ddescribemux=Thread.Mutex(); closemux=Thread.Mutex(); prepbufferready=Thread.Condition(); prepbuffermux=Thread.Mutex();
-
_
portalbuffersize=portalbuffersize;
+
portalbuffersize=
_
portalbuffersize;
_alltext = !alltyped; _params = params; _forcetext = forcetext; _state = PORTALINIT; } //! Returns the command-complete status for this query. //! //! @seealso //! @[affected_rows()] //! //! @note //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface. string status_command_complete() {
-
return
_
statuscmdcomplete;
+
return statuscmdcomplete;
} //! Returns the number of affected rows by this query. //! //! @seealso //! @[status_command_complete()] //! //! @note //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface. int affected_rows() { int rows;
-
if(
_
statuscmdcomplete)
-
sscanf(
_
statuscmdcomplete,"%*s %d",rows);
+
if(statuscmdcomplete)
+
sscanf(statuscmdcomplete,"%*s %d",rows);
return rows; } private void waitfordescribe() { Thread.MutexKey lock=_ddescribemux->lock(); if(!_datarowdesc) _ddescribe->wait(lock); lock=0; }
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:517:
if(!_datarowdesc) waitfordescribe(); trydelayederror(); return sizeof(_datarowdesc); } //! @seealso //! @[Sql.sql_result()->num_rows()] int num_rows() { trydelayederror();
-
return
_
rowsreceived;
+
return rowsreceived;
} private inline void trydelayederror() { if(_delayederror) throwdelayederror(this); } //! @seealso //! @[Sql.sql_result()->eof()] int eof() {
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:679:
case INT4OID: plugbuffer->add_int32(4)->add_int32((int)value); break; case INT2OID: plugbuffer->add_int32(2)->add_int16((int)value); break; } } if(_tprepared) if(_tprepared.datarowdesc)
-
prepbuffer=plugbuffer,
gotdatarowdesc();
+
gotdatarowdesc(
plugbuffer
);
else if(dontcacheprefix->match(_query)) // Don't cache FETCH/COPY m_delete(pgsqlsess->_prepareds,_query),_tprepared=0;
-
if(
!prepbuffer
) {
+
if(
prepbufferready
) {
Thread.MutexKey lock=prepbuffermux->lock(); prepbuffer=plugbuffer; catch(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
)
+
if
(_tprepared
)
+
_tprepared.datarowdesc=datarowdesc;
+
if(
prepbufferready
)
Thread.Thread(gotdatarowdesc); // Do not use callout, it deadlocks
-
if(tp)
-
tp.datarowdesc=datarowdesc;
+
}
-
private void gotdatarowdesc() {
+
private void gotdatarowdesc(
void|Stdio.Buffer plugbuffer
) {
Thread.MutexKey lock=prepbuffermux->lock();
-
+
if(!plugbuffer) {
if(!prepbuffer) catch(prepbufferready->wait(lock));
-
destruct(prepbufferready);
+
plugbuffer=prepbuffer;
+
prepbuffer=0; // Free memory when plugbuffer leaves scope
+
}
+
if(!prepbufferready || _state==CLOSED)
+
lock=_unnamedstatementkey=0;
+
else {
+
destruct(prepbufferready);
// Make sure we do this exactly once
lock=0;
-
if(_state==CLOSED)
-
return;
-
Stdio.Buffer plugbuffer=prepbuffer;
-
prepbuffer=0; // Free memory early
+
plugbuffer->add_int16(sizeof(_datarowdesc)); if(sizeof(_datarowdesc)) foreach(_datarowdesc;;mapping col) plugbuffer->add_int16(oidformat(col.type)); else if(commitprefix->match(_query)) {
-
Thread.MutexKey
lock=pgsqlsess->_commitmux->lock();
+
lock=pgsqlsess->_commitmux->lock();
if(pgsqlsess->_portalsinflight) { 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;
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:737:
_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); }
+
}
final void _openportal() { pgsqlsess->_portalsinflight++; Thread.MutexKey lock=closemux->lock(); _state=BOUND; lock=0;
-
_
statuscmdcomplete=UNDEFINED;
+
statuscmdcomplete=UNDEFINED;
} final void _purgeportal() { _unnamedportalkey=_unnamedstatementkey=0; Thread.MutexKey lock=closemux->lock(); _fetchlimit=0; // disables further Executes switch(_state) { case COPYINPROGRESS: case BOUND:
-
_
datarows->write(1); // Signal EOF
+
datarows->write(1);
// Signal EOF
--pgsqlsess->_portalsinflight; } _state=CLOSED; lock=0; releaseconditions(); } final int _closeportal(bufcon plugbuffer) { int retval=KEEP; PD("%O Try Closeportal %d\n",_portalname,_state);
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:804:
} else if(!alreadyfilled) pgsqlsess->_readyforquerycount++, retval=SYNCSEND; pgsqlsess->_pportalcount=0; } lockc=0; } 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);
+
final void _processdataready(
array datarow
) {
+
inflight--;
+
datarows->write(datarow);
+
rowsreceived++;
+
if(rowsreceived==1)
+
PD("<%O _fetchlimit %d=min(%d||1,%d), inflight %d\n",_portalname,
+
_fetchlimit,(portalbuffersize>>1)*rowsreceived/_bytesreceived,
+
pgsqlsess._fetchlimit,inflight);
if(_fetchlimit) { _fetchlimit=
-
min((
_
portalbuffersize>>1)*
_
rowsreceived/_bytesreceived||1,
+
min((portalbuffersize>>1)*rowsreceived/_bytesreceived||1,
pgsqlsess._fetchlimit); Thread.MutexKey lock=closemux->lock();
-
if(_fetchlimit &&
_
inflight<=_fetchlimit-1)
+
if(_fetchlimit && inflight<=_fetchlimit-1)
_sendexecute(_fetchlimit); else if(!_fetchlimit)
-
PD("<%O _fetchlimit %d,
_
inflight %d, skip execute\n",
-
_portalname,_fetchlimit,
_
inflight);
+
PD("<%O _fetchlimit %d, inflight %d, skip execute\n",
+
_portalname,_fetchlimit,inflight);
lock=0; } } private void releaseconditions() { pgsqlsess=0; Thread.MutexKey lock; if(prepbufferready) { Thread.MutexKey lock=prepbuffermux->lock(); catch(prepbufferready->signal()); } if(!_datarowdesc) { lock=_ddescribemux->lock(); _datarowdesc=({}); _ddescribe->broadcast(); } lock=0; }
-
final void _releasesession() {
-
_
inflight=0;
-
_
datarows->write(1); // Signal EOF
+
final void _releasesession(
void|string statusccomplete
) {
+
if(statusccomplete && !statuscmdcomplete)
+
statuscmdcomplete=statusccomplete;
+
inflight=0;
+
datarows->write(1);
// Signal EOF
conxion plugbuffer=c->start(1); plugbuffer->sendcmd(_closeportal(plugbuffer)); releaseconditions(); } protected void destroy() { catch { // inside destructors, exceptions don't work _releasesession(); }; }
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:863:
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;
+
inflight+=fetchlimit, flushmode=FLUSHSEND;
plugbuffer->sendcmd(flushmode,this); } //! @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()] array(mixed) fetch_row() { int|array datarow;
-
if(arrayp(datarow=
_
datarows->try_read()))
+
if(arrayp(datarow=datarows->try_read()))
return datarow; if(!eoffound) { if(!datarow && (PD("%O Block for datarow\n",_portalname),
-
arrayp(datarow=
_
datarows->read())))
+
arrayp(datarow=datarows->read())))
return datarow; eoffound=1;
-
_
datarows->write(1); // Signal EOF for other threads
+
datarows->write(1);
// Signal EOF for other threads
} trydelayederror(); return 0; } //! @returns //! Multiple result rows at a time (at least one). //! //! 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()] array(array(mixed)) fetch_row_array() { if(eoffound) return 0;
-
array(array|int) datarow=
_
datarows->try_read_array();
+
array(array|int) datarow=datarows->try_read_array();
if(!datarow)
-
datarow=
_
datarows->read_array();
+
datarow=datarows->read_array();
if(arrayp(datarow[-1])) return datarow; trydelayederror(); eoffound=1;
-
_
datarows->write(1); // Signal EOF for other threads
+
datarows->write(1);
// Signal EOF for other threads
return (datarow=datarow[..<1]); } //! @param copydata //! 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
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:938:
PD("CopyData\n"); c->start()->add_int8('d')->add_hstring(copydata,4,4)->sendcmd(SENDOUT); } else _releasesession(); } private void run_result_cb( function(sql_result, array(mixed), mixed ...:void) callback, array(mixed) args) { int|array datarow;
-
while(arrayp(datarow=
_
datarows->read_array()))
+
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). //!
pike.git/lib/modules/Sql.pmod/pgsql_util.pmod:962:
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(sql_result, array(array(mixed)), mixed ...:void) callback, array(mixed) args) { array(array|int) datarow;
-
while((datarow=
_
datarows->read_array()) && arrayp(datarow[-1]))
+
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