From ea77efbad13dbe26ee1c123be56f3cbdec59df40 Mon Sep 17 00:00:00 2001 From: "Stephen R. van den Berg" <srb@cuci.nl> Date: Fri, 4 Jul 2008 10:25:39 +0200 Subject: [PATCH] Enable true bindings for Postgres Rev: lib/modules/Sql.pmod/postgres.pike:1.30 Rev: src/modules/Postgres/postgres.c:1.62 --- lib/modules/Sql.pmod/postgres.pike | 42 +++++++++++++- src/modules/Postgres/postgres.c | 89 ++++++++++++++++++++++++++---- 2 files changed, 117 insertions(+), 14 deletions(-) diff --git a/lib/modules/Sql.pmod/postgres.pike b/lib/modules/Sql.pmod/postgres.pike index f9428b1fd4..21b51ce8ad 100644 --- a/lib/modules/Sql.pmod/postgres.pike +++ b/lib/modules/Sql.pmod/postgres.pike @@ -1,7 +1,7 @@ /* * This is part of the Postgres module for Pike. * - * $Id: postgres.pike,v 1.29 2008/06/28 16:49:55 nilsson Exp $ + * $Id: postgres.pike,v 1.30 2008/07/04 08:25:39 srb Exp $ * */ @@ -384,9 +384,47 @@ array(mapping(string:mixed)) list_fields (string table, void|string wild) //! @[Sql.Sql], @[Sql.sql_result] int|object big_query(object|string q, mapping(string|int:mixed)|void bindings) { + if(stringp(q) && String.width(q)>8) + q=string_to_utf8(q); if (!bindings) return ::big_query(q); - return ::big_query(.sql_util.emulate_bindings(q, bindings, this)); + int pi=0,rep=0; + array(string|int) paramValues=allocate(sizeof(bindings)*2); + array(string) from=allocate(sizeof(bindings)); + array(string) to=allocate(sizeof(bindings)); + foreach(bindings; mixed name; mixed value) { + // Throws if mapping key is empty string. + if(stringp(name)) { + if(name[0]!=':') + name=":"+name; + if(name[1]=='_') { + // Special parameter + continue; + } + } + from[rep]=name; + string rval; + if(multisetp(value)) { + rval=sizeof(value) ? indices(value)[0] : ""; + } + else { + paramValues[pi++]=name[sizeof(name)-1]=='_'; // Force binary mode + if(zero_type(value)) // when name ends in _ + paramValues[pi++]=UNDEFINED; + else { + if(stringp(value) && String.width(value)>8) + value=string_to_utf8(value); + paramValues[pi++]=(string)value; + } + rval="$"+(string)(pi/2); + } + to[rep++]=rval; + } + paramValues= pi ? paramValues[..pi-1] : UNDEFINED; + if(rep--) { + q=replace(q,from[..rep],to[..rep]); + } + return ::big_query(q, paramValues); } #else diff --git a/src/modules/Postgres/postgres.c b/src/modules/Postgres/postgres.c index 4c8b9bb4b5..02d467556a 100644 --- a/src/modules/Postgres/postgres.c +++ b/src/modules/Postgres/postgres.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: postgres.c,v 1.61 2008/06/30 12:10:48 srb Exp $ +|| $Id: postgres.c,v 1.62 2008/07/04 08:25:39 srb Exp $ */ /* @@ -29,6 +29,7 @@ #include <string.h> /* Pike includes */ +#include "svalue.h" #include "las.h" #include "machine.h" #include "pike_memory.h" @@ -381,21 +382,75 @@ static void f_big_query(INT32 args) PGconn *conn = THIS->dblink; PGresult * res; PGnotify * notification; - char *query; + struct array *bnds = 0; + char *query = 0; int lastcommit,docommit,dofetch; + int cnt; + int nParams = 0; + const char** paramValues = 0; + int* paramLengths = 0; + int* paramFormats = 0; + int resultFormat = 0; + PQ_FETCH(); docommit=dofetch=0; lastcommit=THIS->lastcommit; - check_all_args("Postgres->big_query",args,BIT_STRING,0); + check_all_args("Postgres->big_query",args, + BIT_STRING, + BIT_VOID | BIT_ARRAY, + 0); if (!conn) Pike_error ("Not connected.\n"); - if (Pike_sp[-args].u.string->len) + switch(args) + { + default: + if(Pike_sp[1-args].type == PIKE_T_ARRAY) + bnds=Pike_sp[1-args].u.array; + + case 1: + query=" "; + if(Pike_sp[-args].u.string->len) query=Pike_sp[-args].u.string->str; - else - query=" "; + } + + if(bnds && (cnt=bnds->size)) { + int i; + struct svalue *item; + + if(cnt & 1) + Pike_error ("Uneven number of arrayelements.\n"); + + nParams=cnt=cnt/2; + + paramValues = xalloc(cnt*sizeof*paramValues); + paramLengths = xalloc(cnt*sizeof*paramLengths); + paramFormats = xalloc(cnt*sizeof*paramFormats); + + for (i=0,item=bnds->item; cnt--; item++,i++) { + + if (item->type != PIKE_T_INT) + Pike_error ("Expected integer element.\n"); + paramFormats[i] = item->u.integer ? 1 : 0; + switch((++item)->type) + { case PIKE_T_STRING: + paramValues[i] = item->u.string->str; + paramLengths[i] = item->u.string->len; + break; + case PIKE_T_INT: + case T_VOID: + paramValues[i] = 0; /* NULL */ + paramLengths[i] = 0; + break; + default: + Pike_error ("Expected string or UNDEFINED element, Got %d.\n", + item->type); + break; + } + } + } THREADS_ALLOW(); PQ_LOCK(); @@ -431,11 +486,13 @@ static void f_big_query(INT32 args) strcpy(nquery+CPREFLEN-1,query); if(lastcommit) goto yupbegin; - res=PQexec(conn,nquery); + res=PQexecParams(conn,nquery, + nParams,0,paramValues,paramLengths,paramFormats,resultFormat); if(PQstatus(conn) != CONNECTION_OK) { PQclear(res); PQreset(conn); - res=PQexec(conn,nquery); + res=PQexecParams(conn,nquery, + nParams,0,paramValues,paramLengths,paramFormats,resultFormat); } if(res) switch(PQresultStatus(res)) { @@ -444,7 +501,8 @@ static void f_big_query(INT32 args) yupbegin: res=PQexec(conn,"BEGIN"); if(res && PQresultStatus(res)==PGRES_COMMAND_OK) { PQclear(res); - res=PQexec(conn,nquery); + res=PQexecParams(conn,nquery,nParams,0, + paramValues,paramLengths,paramFormats,resultFormat); if(res && PQresultStatus(res)==PGRES_COMMAND_OK) docommit=1; else { @@ -470,7 +528,8 @@ yupbegin: res=PQexec(conn,"BEGIN"); } lastcommit=0; if(!res) - res=PQexec(conn,query); + res=PQexecParams(conn,query, + nParams,0,paramValues,paramLengths,paramFormats,resultFormat); /* A dirty hack to fix the reconnect bug. * we don't need to store the host/user/pass/db... etc.. * PQreset() does all the job. @@ -481,7 +540,8 @@ yupbegin: res=PQexec(conn,"BEGIN"); (PQresultStatus(res) == PGRES_BAD_RESPONSE)) { PQclear(res); PQreset(conn); - res=PQexec(conn,query); + res=PQexecParams(conn,query, + nParams,0,paramValues,paramLengths,paramFormats,resultFormat); } notification=PQnotifies(conn); @@ -491,6 +551,10 @@ yupbegin: res=PQexec(conn,"BEGIN"); THIS->dofetch=dofetch; THIS->lastcommit=lastcommit; + if (bnds) { + xfree(paramValues); xfree(paramLengths); xfree(paramFormats); + } + pop_n_elems(args); if (notification!=NULL) { pgdebug("Incoming notification: \"%s\"\n",notification->relname); @@ -764,7 +828,8 @@ PIKE_MODULE_INIT ADD_FUNCTION("select_db", f_select_db, tFunc(tStr,tVoid), 0); /* function(string:int|object) */ - ADD_FUNCTION("big_query", f_big_query, tFunc(tStr,tOr(tInt,tObj)), 0); + ADD_FUNCTION("big_query", f_big_query, + tFunc(tStr tOr(tVoid,tArr(tOr3(tInt,tStr,tVoid))), tOr(tInt,tObj)), 0); /* function(void:string) */ ADD_FUNCTION("error", f_error, tFunc(tVoid,tStr), 0); -- GitLab