pike.git
/
lib
/
modules
/
Sql.pmod
/
pgsql.pike
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/lib/modules/Sql.pmod/pgsql.pike:96:
int _packetssent; // Number of packets sent int _bytessent; // Number of bytes sent private int warningsdropcount; // Number of uncollected warnings private int prepstmtused; // Number of times prepared statements were used private int warningscollected; private int invalidatecache; private int connectionclosed; private string host, database, user, pass; private int port;
+
private multiset cachealways=(<"BEGIN","begin","END","end","COMMIT","commit">);
private object createprefix =Regexp("^[ \t\f\r\n]*[Cc][Rr][Ee][Aa][Tt][Ee][ \t\f\r\n]"); private object dontcacheprefix =Regexp("^[ \t\f\r\n]*([Ff][Ee][Tt][Cc][Hh]|[Cc][Oo][Pp][Yy])[ \t\f\r\n]");
-
private object
limitpostfix
-
=Regexp("[ \t\f\r\n][Ll][Ii][Mm][Ii][Tt][ \t\f\r\n]+[12][; \t\f\r\n]*$");
+
private object
execfetchlimit
+
=Regexp("
^
[ \t\f\r\n]
*((
[
Uu][Pp][Dd][Aa]|[Dd][Ee][
Ll][
Ee])[Tt][Ee]|\
+
[
Ii][
Nn][Ss][Ee][Rr][Tt])[ \t\f\r\n]|\
+
[ \t\f\r\n][Ll][Ii][
Mm][Ii][Tt][ \t\f\r\n]+[12][; \t\f\r\n]*$");
Thread.Mutex _querymutex; Thread.Mutex _stealmutex; #define USERERROR(msg) throw(({(msg), backtrace()[..<1]})) protected string _sprintf(int type, void|mapping flags) { string res=UNDEFINED; switch(type) { case 'O': res=sprintf(DRIVERNAME"(%s@%s:%d/%s,%d)",
pike.git/lib/modules/Sql.pmod/pgsql.pike:169:
//! //! @param database //! Specifies the database to connect to. Not specifying this is //! only supported if the PostgreSQL backend has a default database //! configured. If you do not want to connect to any live database, //! you can use @expr{"template1"@}. //! //! @param options //! Currently supports at least the following: //! @mapping
+
//! @member int "reconnect"
+
//! Set it to zero to disable automatic reconnects upon losing
+
//! the connection to the database. Not setting it, or setting
+
//! it to one, will cause one timed reconnect to take place.
+
//! Setting it to -1 will cause the system to try and reconnect
+
//! indefinitely.
//! @member int "use_ssl" //! If the database supports and allows SSL connections, the session //! will be SSL encrypted, if not, the connection will fallback
-
//! to plain unencrypted
+
//! to plain unencrypted
.
//! @member int "force_ssl" //! If the database supports and allows SSL connections, the session
-
//! will be SSL encrypted, if not, the connection will abort
+
//! will be SSL encrypted, if not, the connection will abort
.
+
//! @member int "text_query"
+
//! Send queries to and retrieve results from the database using text
+
//! instead of the, generally more efficient, default native binary method.
+
//! Turning this on will allow multiple statements per query separated
+
//! by semicolons.
//! @member int "cache_autoprepared_statements" //! If set to zero, it disables the automatic statement prepare and //! cache logic; caching prepared statements can be problematic //! when stored procedures and tables are redefined which leave stale
-
//! references in the already cached prepared statements
+
//! references in the already cached prepared statements
.
//! @member string "client_encoding" //! Character encoding for the client side, it defaults to using //! the default encoding specified by the database, e.g. //! @expr{"UTF8"@} or @expr{"SQL_ASCII"@}. //! @member string "standard_conforming_strings" //! When on, backslashes in strings must not be escaped any longer,
-
//! @[quote()] automatically adjusts quoting strategy accordingly
+
//! @[quote()] automatically adjusts quoting strategy accordingly
.
//! @member string "escape_string_warning" //! When on, a warning is issued if a backslash (\) appears in an //! ordinary string literal and @expr{"standard_conforming_strings"@} //! is off, defaults to on. //! @endmapping //! For the numerous other options please check the PostgreSQL manual. //! //! @note //! You need to have a database selected before using the sql-object, //! otherwise you'll get exceptions when you try to query it. Also //! notice that this function @b{can@} raise exceptions if the db //! server doesn't respond, if the database doesn't exist or is not //! accessible by you. //! //! @seealso //! @[Postgres.postgres], @[Sql.Sql], @[select_db()],
-
//! @url{http://
search
.postgresql.org/search?u=%2Fdocs%2F&q=client+connection+defaults@}
+
//! @url{http://
www
.postgresql.org/search
/
?u=%2Fdocs%
2Fcurrent%
2F&q=client+connection+defaults@}
protected void create(void|string _host, void|string _database, void|string _user, void|string _pass, void|mapping(string:mixed) _options) { pass = _pass; _pass = "CENSORED"; if(pass) String.secure(pass); user = _user; database = _database; host = _host || PGSQL_DEFAULT_HOST; options = _options || ([]); if(has_value(host,":") && sscanf(_host,"%s:%d",host,port)!=2) ERROR("Error in parsing the hostname argument\n"); if(!port) port = PGSQL_DEFAULT_PORT;
-
+
_runtimeparameter=([]);
_querymutex=Thread.Mutex(); _stealmutex=Thread.Mutex(); reconnect(); } //! @returns //! The textual description of the last //! server-related error. Returns @expr{0@} if no error has occurred //! yet. It is not cleared upon reading (can be invoked multiple //! times, will return the same result until a new error occurs).
pike.git/lib/modules/Sql.pmod/pgsql.pike:258:
//! This function returns a string describing what host are we talking to, //! and how (TCP/IP or UNIX sockets). //! //! @seealso //! @[server_info()] string host_info() { return sprintf("fd:%d TCP/IP %s:%d PID %d", _c?_c.query_fd():-1,host,port,backendpid); }
+
//! Returns true if the connection seems to be open.
+
//!
+
//! @note
+
//! This function only checks that there's an open connection,
+
//! 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()
+
{ return _c&&_c.query_fd()>=0;
+
}
+
+
//! @decl int ping()
+
//!
+
//! Check whether the connection is alive.
+
//!
+
//! @returns
+
//! Returns one of the following:
+
//! @int
+
//! @value 0
+
//! Everything ok.
+
//! @value 1
+
//! The connection reconnected automatically.
+
//! @value -1
+
//! The server has gone away, and the connection is dead.
+
//! @endint
+
//!
+
//! @seealso
+
//! @[is_open()]
+
int ping()
+
{ int oldbackendpid=backendpid;
+
mixed err;
+
if(_c && (err = catch
+
{ _c.sendflush();
+
return backendpid!=oldbackendpid;
+
}))
+
{ PD("%O\n",err);
+
if(reconnect(1))
+
return 1;
+
}
+
return -1;
+
}
+
final private object getsocket(void|int nossl) { object lcon = Stdio.File(); if(!lcon.connect(host,port)) return UNDEFINED; object fcon; #if constant(SSL.sslfile) if(!nossl && (options->use_ssl || options->force_ssl)) { PD("SSLRequest\n"); { object c=.pgsql_util.PGassist();
pike.git/lib/modules/Sql.pmod/pgsql.pike:324:
} //! 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. //! //! @seealso //! @[get_charset()], @[create()],
-
//! @url{http://
search
.postgresql.org/search?u=%2Fdocs%2F&q=character+sets@}
+
//! @url{http://
www
.postgresql.org/search
/
?u=%2Fdocs%
2Fcurrent%
2F&q=character+sets@}
void set_charset(string charset) { big_query(sprintf("SET CLIENT_ENCODING TO '%s'",quote(charset))); } //! @returns //! The PostgreSQL name for the current connection charset. //! //! @seealso //! @[set_charset()], @[getruntimeparameters()],
-
//! @url{http://
search
.postgresql.org/search?u=%2Fdocs%2F&q=character+sets@}
+
//! @url{http://
www
.postgresql.org/search
/
?u=%2Fdocs%
2Fcurrent%
2F&q=character+sets@}
string get_charset() { return _runtimeparameter[CLIENT_ENCODING]; } //! @returns //! Currently active runtimeparameters for //! the open session; these are initialised by the @tt{options@} parameter //! during session creation, and then processed and returned by the server. //! Common values are: //! @mapping //! @member string "client_encoding" //! Character encoding for the client side, e.g. //! @expr{"UTF8"@} or @expr{"SQL_ASCII"@}. //! @member string "server_encoding" //! Character encoding for the server side as determined when the
-
//! database was created, e.g. @expr{"UTF8"@} or @expr{"SQL_ASCII"@}
+
//! database was created, e.g. @expr{"UTF8"@} or @expr{"SQL_ASCII"@}
.
//! @member string "DateStyle"
-
//! Date parsing/display, e.g. @expr{"ISO, DMY"@}
+
//! Date parsing/display, e.g. @expr{"ISO, DMY"@}
.
//! @member string "TimeZone"
-
//! Default timezone used by the database, e.g. @expr{"localtime"@}
+
//! Default timezone used by the database, e.g. @expr{"localtime"@}
.
//! @member string "standard_conforming_strings"
-
//! When on, backslashes in strings must not be escaped any longer
+
//! When on, backslashes in strings must not be escaped any longer
.
//! @member string "session_authorization"
-
//! Displays the authorisationrole which the current session runs under
+
//! Displays the authorisationrole which the current session runs under
.
//! @member string "is_superuser" //! Indicates if the current authorisationrole has database-superuser
-
//! privileges
+
//! privileges
.
//! @member string "integer_datetimes"
-
//! Reports wether the database supports 64-bit-integer dates and times
+
//! Reports wether the database supports 64-bit-integer dates and times
.
//! @member string "server_version"
-
//! Shows the server version, e.g. @expr{"8.3.3"@}
+
//! Shows the server version, e.g. @expr{"8.3.3"@}
.
//! @endmapping //! //! The values can be changed during a session using SET commands to the //! database. //! For other runtimeparameters check the PostgreSQL documentation. //! //! @seealso
-
//! @url{http://
search
.postgresql.org/search?u=%2Fdocs%2F&q=client+connection+defaults@}
+
//! @url{http://
www
.postgresql.org/search
/
?u=%2Fdocs%
2Fcurrent%
2F&q=client+connection+defaults@}
//! //! @note //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface. mapping(string:string) getruntimeparameters() { return _runtimeparameter+([]); } //! @returns //! A set of statistics for the current session:
pike.git/lib/modules/Sql.pmod/pgsql.pike:533:
final private string pinpointerror(void|string query,void|string offset) { if(!query) return ""; int k=(int)offset; if(k<=0) return MARKSTART+query+MARKEND; return MARKSTART+(k>1?query[..k-2]:"")+MARKERROR+query[k-1..]+MARKEND; } private void phasedreconnect()
+
{ if(!connectionclosed)
{ connectionclosed=1; if(!reconnect(1)) { sleep(RECONNECTDELAY); if(!reconnect(1))
-
{ sleep(RECONNECTBACKOFF);
-
reconnect(1);
+
{
do
sleep(RECONNECTBACKOFF);
+
while(!
reconnect(1)
&& options->reconnect==-1)
;
} } }
-
+
}
final int _decodemsg(void|state waitforstate) { #ifdef DEBUG { array line; #ifdef DEBUGMORE line=backtrace(); #endif PD("Waiting for state %O %O\n",waitforstate,line&&line[sizeof(line)-2]); }
pike.git/lib/modules/Sql.pmod/pgsql.pike:750:
{ string s; msglen-=sizeof(s=_c.getstring())+1; mapping(string:mixed) res=(["name":s]); msglen-=4+2+4+2+4+2; res->tableoid=_c.getint32()||UNDEFINED; res->tablecolattr=_c.getint16()||UNDEFINED; res->type=_c.getint32(); { int len=_c.getint16(); res->length=len>=0?len:"variable"; }
-
res->atttypmod=_c.getint32();res->formatcode=_c.getint16();
+
res->atttypmod=_c.getint32();
+
res->formatcode=_c.getint16();
// Currently broken in Postgres
a[i]=res; } #ifdef DEBUGMORE PD("%O\n",a); #endif if(_c.portal) _c.portal->_datarowdesc=a; _mstate=gotrowdescription; break; }
pike.git/lib/modules/Sql.pmod/pgsql.pike:784:
{ if(tprepared) storetiming(); #ifdef USEPGsql _c.decodedatarow(msglen);msglen=0; #else array a, datarowdesc; _c.portal->_bytesreceived+=msglen; datarowdesc=_c.portal->_datarowdesc; int cols=_c.getint16(); int atext = _c.portal->_alltext; // cache locally for speed
+
int forcetext = _c.portal->_forcetext; // cache locally for speed
string cenc=_runtimeparameter[CLIENT_ENCODING]; a=allocate(cols,UNDEFINED); msglen-=2+4*cols;
-
foreach(
a
;int i;)
+
foreach(
datarowdesc
;int i;
mapping m
)
{ int collen=_c.getint32(); if(collen>0) { msglen-=collen; mixed value;
-
switch(
datarowdesc[i]
->type)
-
{
default
:value=_c.getstring(collen);
+
switch(
int typ=m
->type)
+
{
case FLOAT4OID
:
+
#if SIZEOF_FLOAT>=8
+
case FLOAT8OID:
+
#endif
+
if(!atext)
+
{
value=
(float)
_c.getstring(collen);
break;
-
case
TEXTOID:
-
case BPCHAROID:
-
case VARCHAROID
:
-
value=_c.getstring(collen);
-
if(cenc==UTF8CHARSET && catch(value=utf8_to_string(value)))
-
ERROR("%O contains non-%s characters\n",value,UTF8CHARSET);
+
}
+
default
:value=_c.getstring(collen);
break;
-
case CHAROID:value=atext?_c.getstring(1):_c.getbyte();
+
case CHAROID:
+
value=atext?_c.getstring(1):_c.getbyte();
break; case BOOLOID:value=_c.getbyte();
-
+
switch(value)
+
{ case 'f':value=0;
+
break;
+
case 't':value=1;
+
}
if(atext) value=value?"t":"f"; break;
-
case
INT8OID
:
value=_c.getint64();
-
break;
-
#if SIZEOF_FLOAT>=8
-
case
FLOAT8OID
:
-
#endif
-
case
FLOAT4OID
:
+
case
TEXTOID
:
+
case
BPCHAROID
:
+
case
VARCHAROID
:
value=_c.getstring(collen);
-
+
if(cenc==UTF8CHARSET && catch(value=utf8_to_string(value)))
+
ERROR("%O contains non-%s characters\n",value,UTF8CHARSET);
+
break;
+
case INT8OID:case INT2OID:
+
case OIDOID:case INT4OID:
+
if(forcetext)
+
{ value=_c.getstring(collen);
if(!atext)
-
value=(
float
)value;
+
value=(
int
)value;
+
}
+
else
+
{ switch(typ)
+
{ case INT8OID:value=_c.getint64();
break; case INT2OID:value=_c.getint16(); break; case OIDOID: case INT4OID:value=_c.getint32(); }
-
if(atext
&&!stringp(value
)
)
+
if(atext)
value=(string)value;
-
+
}
+
}
a[i]=value; } else if(!collen) a[i]=""; } a=({a}); _c.portal->_datarows+=a; _c.portal->_inflight-=sizeof(a); #endif }
pike.git/lib/modules/Sql.pmod/pgsql.pike:908:
}; warningsdropcount+=warningscollected; warningscollected=0; switch(msgresponse->C) { case "P0001": lastmessage=({sprintf("%s: %s",msgresponse->S,msgresponse->M)}); USERERROR(a2nls(lastmessage +({pinpointerror(_c.portal->_query,msgresponse->P)}) +showbindings())); case "57P01":case "57P02":case "57P03":
-
preplastmessage();phasedreconnect();
-
PD(a2nls(lastmessage));
+
preplastmessage();phasedreconnect();PD(a2nls(lastmessage));
USERERROR(a2nls(lastmessage)); case "08P01":case "42P05": errtype=protocolerror; case "XX000":case "42883":case "42P01": invalidatecache=1; default: preplastmessage(); if(msgresponse->D) lastmessage+=({msgresponse->D}); if(msgresponse->H)
pike.git/lib/modules/Sql.pmod/pgsql.pike:1040:
if(_c) { reconnected++; prepstmtused=0; if(!force) _c.sendterminate(); else _c.close(); _c=0; foreach(prepareds;;mapping tp) m_delete(tp,"preparedname");
-
if(!(connectmtxkey = _stealmutex.trylock(2)))
+
if(!
options->reconnect || !
(connectmtxkey = _stealmutex.trylock(2)))
return 0; // Recursive reconnect, bailing out } if(!(_c=getsocket())) { string msg=sprintf("Couldn't connect to database on %s:%d",host,port); if(force)
-
{ lastmessage+=({msg});
+
{
if(!sizeof(lastmessage) || lastmessage[sizeof(lastmessage)-1]!=msg)
+
lastmessage+=({msg});
return 0; } else ERROR(msg+"\n"); } _closesent=0; _mstate=unauthenticated; qstate=queryidle;
-
_runtimeparameter
=
([])
;
+
portalsinflight
=
unnamedportalinuse=0
;
array(string) plugbuf=({"",_c.plugint32(PG_PROTOCOL(3,0))}); if(user) plugbuf+=({"user\0",user,"\0"}); if(database) plugbuf+=({"database\0",database,"\0"});
-
foreach
(options-(<"use_ssl","force_ssl","cache_autoprepared_statements">);
+
options->reconnect=zero_type
(options-
>reconnect) || options->reconnect;
+
foreach
(
(options+_runtimeparameter)
+
-(
<"use_ssl","force_ssl","cache_autoprepared_statements"
,"reconnect",
+
"text_query","is_superuser","server_encoding","server_version",
+
"integer_datetimes","session_authorization"
>);
string name;mixed value) plugbuf+=({name,"\0",(string)value,"\0"}); plugbuf+=({"\0"}); int len=4; foreach(plugbuf;;string s) len+=sizeof(s); plugbuf[0]=_c.plugint32(len); _c.write(plugbuf); PD("%O\n",plugbuf); { mixed err=catch(_decodemsg(readyforquery));
pike.git/lib/modules/Sql.pmod/pgsql.pike:1121:
//! //! @seealso //! @[cancelquery()], @[reload()] //! //! @note //! This function is PostgreSQL-specific, and thus it is not available //! through the generic SQL-interface. void resync(void|int special) { mixed err; int didsync;
+
if(!is_open()&&!reconnect(1))
+
ERROR(a2nls(lastmessage));
if(err = catch { sendclose(1); PD("Portalsinflight: %d\n",portalsinflight); if(!portalsinflight) { if(!earlyclose) { PD("Sync\n"); _c.sendcmd(({"S",_c.plugint32(4)}),2); } didsync=1; if(!special)
pike.git/lib/modules/Sql.pmod/pgsql.pike:1584:
//! //! 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. //! //! 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
+
//! for the query at hand. Potentially more efficient than the default
+
//! binary method for simple queries with small or no result sets.
+
//! Note that this mode causes all but the first query result of a list
+
//! of semicolon separated statements to be discarded.
//! @endmapping //! //! @returns //! A @[Sql.pgsql_util.pgsql_result] object (which conforms to the //! @[Sql.sql_result] standard interface for accessing data). It is //! recommended to use @[Sql.Sql()->query()] for simpler queries (because //! it is easier to handle, but stores all the result in memory), and //! @[Sql.Sql()->big_query()] for queries you expect to return huge amounts of //! data (it's harder to handle, but fetches results on demand). //! //! @note //! This function @b{can@} raise exceptions. //! //! @note //! This function supports multiple simultaneous queries (portals) on a single //! database connection. This is a feature not commonly supported by other //! database backends. //! //! @note
-
//! This function does not support multiple queries in one querystring.
+
//! This function
,
by default,
does not support multiple queries in one
+
//!
querystring.
//! I.e. it allows for but does not require a trailing semicolon, but it //! simply ignores any commands after the first unquoted semicolon. This can //! be viewed as a limited protection against SQL-injection attacks.
-
+
//! To make it support multiple queries in one querystring, use the
+
//! @ref{:_text@} option.
//! //! @seealso //! @[big_typed_query()], @[Sql.Sql], @[Sql.sql_result], //! @[Sql.Sql()->query()], @[Sql.pgsql_util.pgsql_result] object big_query(string q,void|mapping(string|int:mixed) bindings, void|int _alltyped) { string preparedname=""; string portalname=""; int forcecache=-1;
-
+
int forcetext=options->text_query;
string cenc=_runtimeparameter[CLIENT_ENCODING]; switch(cenc) { 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;
pike.git/lib/modules/Sql.pmod/pgsql.pike:1640:
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) { case ":_cache":forcecache=(int)value; break;
+
case ":_text":forcetext=(int)value;
+
break;
} continue; } if(!has_value(q,name)) continue; } from[rep]=name; string rval; if(multisetp(value)) // multisets are taken literally rval=indices(value)*","; // and bypass the encoding logic
pike.git/lib/modules/Sql.pmod/pgsql.pike:1669:
from=({from,to,paramValues}); } else 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; int tstart;
-
if(forcecache==1 || forcecache!=0 && sizeof(q)>=MINPREPARELENGTH)
+
if(
forcetext)
+
{ if(bindings)
+
q = .sql_util.emulate_bindings(q, bindings, this);
+
if(unnamedportalinuse)
+
throw("Unnamed portal in use, needed for simple query");
+
}
+
else if(
forcecache==1
+
|| forcecache!=0 &&
(
sizeof(q)>=MINPREPARELENGTH
|| cachealways[q]
)
)
{ array(string) plugbuf=({}); if(tp=prepareds[q]) { if(tp->preparedname) prepstmtused++, preparedname=tp->preparedname; else if((tstart=tp->trun) && tp->tparse*FACTORPLAN>=tstart && (zero_type(options->cache_autoprepared_statements) || options->cache_autoprepared_statements)) preparedname=PREPSTMTPREFIX+(string)pstmtcount++; }
pike.git/lib/modules/Sql.pmod/pgsql.pike:1711:
} } if(sizeof(plugbuf)) { _c.sendcmd(plugbuf,1); // close expireds PD("%O\n",plugbuf); } tstart=gethrtime(); } // pgsql_result autoassigns to portal else tp=UNDEFINED;
-
connectionclosed=0;
+
for(;;)
-
{ .pgsql_util.pgsql_result(this,q,_fetchlimit,
portalbuffersize,_alltyped,
-
from);
+
{
connectionclosed=0;
+
.pgsql_util.pgsql_result(this,q,_fetchlimit,
+
portalbuffersize,_alltyped,
from
,forcetext
);
if(unnamedportalinuse) portalname=PORTALPREFIX+(string)pportalcount++; else unnamedportalinuse++; _c.portal->_portalname=portalname; qstate=inquery; portalsinflight++; portalsopened++; clearmessage=1; mixed err; if(!(err = catch
-
+
{ if(forcetext)
+
{ _c.sendcmd(({"Q",_c.plugint32(4+sizeof(q)+1),q,"\0"}),1);
+
PD("Simple query: %O\n",q);
+
}
+
else
{ if(!sizeof(preparedname) || !tp || !tp->preparedname) { PD("Parse statement %s\n",preparedname); // 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 _c.sendcmd(({"P",_c.plugint32(4+sizeof(preparedname)+1+sizeof(q)+1+2), preparedname,"\0",q,"\0",_c.plugint16(0)}),3); PD("Query: %O\n",q); } // sends Parameter- and RowDescription for 'S'
pike.git/lib/modules/Sql.pmod/pgsql.pike:1811:
break; } default: { int k; if(!value) { plugbuf+=({_c.plugint32(-1)}); break; } value=(string)value; if(String.width(value)>8)
+
if(dtoid[i]==BYTEAOID)
+
value=string_to_utf8(value);
+
else
ERROR("Wide string %O not supported for type OID %d\n", value,dtoid[i]); len+=k=sizeof(value); plugbuf+=({_c.plugint32(k),value}); break; } case BOOLOID:plugbuf+=({_c.plugint32(1)});len++; do { int tval; if(stringp(value))
pike.git/lib/modules/Sql.pmod/pgsql.pike:1891:
} { array a;int i; len+=(i=sizeof(a=_c.portal->_datarowdesc))*2; plugbuf+=({_c.plugint16(i)}); foreach(a;;mapping col) plugbuf+=({_c.plugint16(oidformat(col->type))}); } plugbuf[1]=_c.plugint32(len); PD("Bind portal %s statement %s\n",portalname,preparedname); _c.sendcmd(plugbuf);
-
#ifdef DEBUGMORE
+
#ifdef
DEBUGMORE
PD("%O\n",plugbuf); #endif } _c.portal->_statuscmdcomplete=UNDEFINED; _sendexecute(_fetchlimit
-
&& !
limitpostfix->match
(q
)
// Optimisation for LIMIT 1
+
&& !(
cachealways[
q
]
+
||
sizeof(q)>=MINPREPARELENGTH
&&
execfetchlimit->match(q))
&& FETCHLIMITLONGRUN); if(tp) { _decodemsg(bindcomplete); int tend=gethrtime(); if(tend==tstart) m_delete(prepareds,q); else { tp->hits++; totalhits++; if(!tp->preparedname) { if(sizeof(preparedname)) tp->preparedname=preparedname; tstart=tend-tstart; if(!tp->tparse || tp->tparse>tstart) tp->tparse=tstart; } tp->trunstart=tend; } tprepared=tp; }
-
+
}
})) break; PD("%O\n",err); resync(1); backendstatus=UNDEFINED; if(!connectionclosed) throw(err); tp=UNDEFINED; } { object tportal=_c.portal; // Make copy, because it might dislodge