added prepared statements in insert and update for DB's which support it (atm. only MaxDB). Atm this need to be switched on by a parameter, as I still have some problems, it off by default

This commit is contained in:
Ralf Becker 2004-10-14 20:58:39 +00:00
parent ba55620f3d
commit a4557c1191

View File

@ -111,6 +111,8 @@
var $privat_Link_ID = False; // do we use a privat Link_ID or a reference to the global ADOdb object var $privat_Link_ID = False; // do we use a privat Link_ID or a reference to the global ADOdb object
var $Query_ID = 0; var $Query_ID = 0;
var $prepared_sql = array(); // sql is the index
/** /**
* @param string $query query to be executed (optional) * @param string $query query to be executed (optional)
*/ */
@ -326,13 +328,14 @@
* Execute a query * Execute a query
* *
* @param string $Query_String the query to be executed * @param string $Query_String the query to be executed
* @param mixed $line the line method was called from - use __LINE__ * @param int $line the line method was called from - use __LINE__
* @param string $file the file method was called from - use __FILE__ * @param string $file the file method was called from - use __FILE__
* @param int $offset row to start from * @param int $offset row to start from, default 0
* @param int $num_rows number of rows to return (optional), if unset will use $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs'] * @param int $num_rows number of rows to return (optional), default -1 = all, 0 will use $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs']
* @param array/boolean $inputarr array for binding variables to parameters or false (default)
* @return ADORecordSet or false, if the query fails * @return ADORecordSet or false, if the query fails
*/ */
function query($Query_String, $line = '', $file = '', $offset=0, $num_rows=-1) function query($Query_String, $line = '', $file = '', $offset=0, $num_rows=-1,$inputarr=false)
{ {
if ($Query_String == '') if ($Query_String == '')
{ {
@ -352,17 +355,17 @@
{ {
$this->Link_ID->SetFetchMode(ADODB_FETCH_BOTH); $this->Link_ID->SetFetchMode(ADODB_FETCH_BOTH);
} }
if (! $num_rows) if (!$num_rows)
{ {
$num_rows = $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs']; $num_rows = $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs'];
} }
if ($num_rows > 0) if ($num_rows > 0)
{ {
$this->Query_ID = $this->Link_ID->SelectLimit($Query_String,$num_rows,(int)$offset); $this->Query_ID = $this->Link_ID->SelectLimit($Query_String,$num_rows,(int)$offset,$inputarr);
} }
else else
{ {
$this->Query_ID = $this->Link_ID->Execute($Query_String); $this->Query_ID = $this->Link_ID->Execute($Query_String,$inputarr);
} }
$this->Row = 0; $this->Row = 0;
$this->Errno = $this->Link_ID->ErrorNo(); $this->Errno = $this->Link_ID->ErrorNo();
@ -370,7 +373,9 @@
if (! $this->Query_ID) if (! $this->Query_ID)
{ {
$this->halt("Invalid SQL: ".$Query_String, $line, $file); $this->halt("Invalid SQL: ".(is_array($Query_String)?$Query_String[0]:$Query_String).
($inputarr ? "<br>Parameters: '".implode("','",$inputarr)."'":''),
$line, $file);
} }
return $this->Query_ID; return $this->Query_ID;
} }
@ -379,15 +384,16 @@
* Execute a query with limited result set * Execute a query with limited result set
* *
* @param string $Query_String the query to be executed * @param string $Query_String the query to be executed
* @param int $offset row to start from * @param int $offset row to start from, default 0
* @param mixed $line the line method was called from - use __LINE__ * @param int $line the line method was called from - use __LINE__
* @param string $file the file method was called from - use __FILE__ * @param string $file the file method was called from - use __FILE__
* @param int $num_rows number of rows to return (optional), if unset will use $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs'] * @param int $num_rows number of rows to return (optional), default -1 = all, 0 will use $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs']
* @param array/boolean $inputarr array for binding variables to parameters or false (default)
* @return ADORecordSet or false, if the query fails * @return ADORecordSet or false, if the query fails
*/ */
function limit_query($Query_String, $offset, $line = '', $file = '', $num_rows = '') function limit_query($Query_String, $offset, $line = '', $file = '', $num_rows = '',$inputarr=false)
{ {
return $this->query($Query_String,$line,$file,$offset,$num_rows); return $this->query($Query_String,$line,$file,$offset,$num_rows,$inputarr);
} }
/** /**
@ -946,7 +952,7 @@
*/ */
function quote($value,$type=False,$not_null=true) function quote($value,$type=False,$not_null=true)
{ {
if ($this->Debug) echo "<p>db::quote('$value','$type')</p>\n"; if ($this->Debug) echo "<p>db::quote(".(is_null($value)?'NULL':"'$value'").",'$type','$not_null')</p>\n";
if (!$not_null && is_null($value)) // writing unset php-variables and those set to NULL now as SQL NULL if (!$not_null && is_null($value)) // writing unset php-variables and those set to NULL now as SQL NULL
{ {
@ -1028,7 +1034,7 @@
$this->halt("db::column_data_implode('$glue',".print_r($array,True).",'$use_key',".print_r($only,True).",<pre>".print_r($column_definitions,True)."</pre><b>nothing known about column '$key'!</b>"); $this->halt("db::column_data_implode('$glue',".print_r($array,True).",'$use_key',".print_r($only,True).",<pre>".print_r($column_definitions,True)."</pre><b>nothing known about column '$key'!</b>");
} }
$column_type = is_array($column_definitions) ? @$column_definitions[$key]['type'] : False; $column_type = is_array($column_definitions) ? @$column_definitions[$key]['type'] : False;
$not_null = is_array($column_definitions) && isset($column_definitions[$key]['nullable']) ? !$column_definitions[$key]['nullable'] : True; $not_null = is_array($column_definitions) && isset($column_definitions[$key]['nullable']) ? !$column_definitions[$key]['nullable'] : false;
if (is_array($data)) if (is_array($data))
{ {
@ -1132,7 +1138,7 @@
* @param string/boolean $app string with name of app or False to use the current-app * @param string/boolean $app string with name of app or False to use the current-app
* @return ADORecordSet or false, if the query fails * @return ADORecordSet or false, if the query fails
*/ */
function insert($table,$data,$where,$line,$file,$app=False) function insert($table,$data,$where,$line,$file,$app=False,$use_prepared_statement=false)
{ {
if ($this->Debug) echo "<p>db::insert('$table',".print_r($data,True).",".print_r($where,True).",$line,$file,'$app')</p>\n"; if ($this->Debug) echo "<p>db::insert('$table',".print_r($data,True).",".print_r($where,True).",$line,$file,'$app')</p>\n";
@ -1165,10 +1171,30 @@
} }
$data = array_merge($where,$data); // the checked values need to be inserted too, value in data has precedence $data = array_merge($where,$data); // the checked values need to be inserted too, value in data has precedence
} }
$sql = "$cmd INTO $table ".$this->column_data_implode(',',$data,'VALUES',False,$table_def['fd']).$sql_append; $inputarr = false;
if ($use_prepared_statement && $this->Link_ID->_bindInputArray) // eg. MaxDB
{
$this->Link_ID->Param(false); // reset param-counter
$cols = array_keys($data);
foreach($cols as $col)
{
$params[] = $this->Link_ID->Param($col);
}
$sql = "$cmd INTO $table (".implode(',',$cols).') VALUES ('.implode(',',$params).')'.$sql_append;
// check if we already prepared that statement
if (!isset($this->prepared_sql[$sql]))
{
$this->prepared_sql[$sql] = $this->Link_ID->Prepare($sql);
}
$sql = $this->prepared_sql[$sql];
$inputarr = &$data;
}
else
{
$sql = "$cmd INTO $table ".$this->column_data_implode(',',$data,'VALUES',False,$table_def['fd']).$sql_append;
}
if ($this->Debug) echo "<p>db::insert('$table',".print_r($data,True).",".print_r($where,True).",$line,$file,'$app') sql='$sql'</p>\n"; if ($this->Debug) echo "<p>db::insert('$table',".print_r($data,True).",".print_r($where,True).",$line,$file,'$app') sql='$sql'</p>\n";
return $this->query($sql,$line,$file); return $this->query($sql,$line,$file,0,-1,$inputarr);
} }
/** /**
@ -1184,7 +1210,7 @@
* @param string/boolean $app string with name of app or False to use the current-app * @param string/boolean $app string with name of app or False to use the current-app
* @return ADORecordSet or false, if the query fails * @return ADORecordSet or false, if the query fails
*/ */
function update($table,$data,$where,$line,$file,$app=False) function update($table,$data,$where,$line,$file,$app=False,$use_prepared_statement=false)
{ {
if ($this->Debug) echo "<p>db::update('$table',".print_r($data,true).','.print_r($where,true).",$line,$file,'$app')</p>\n"; if ($this->Debug) echo "<p>db::update('$table',".print_r($data,true).','.print_r($where,true).",$line,$file,'$app')</p>\n";
$table_def = $this->get_table_definitions($app,$table); $table_def = $this->get_table_definitions($app,$table);
@ -1192,30 +1218,53 @@
$blobs2update = array(); $blobs2update = array();
// SapDB/MaxDB cant update LONG columns / blob's: if a blob-column is included in the update we remember it in $blobs2update // SapDB/MaxDB cant update LONG columns / blob's: if a blob-column is included in the update we remember it in $blobs2update
// and remove it from $data // and remove it from $data
if ($this->Type == 'sapdb') switch ($this->Type)
{ {
// check if data contains any LONG columns case 'sapdb':
foreach($data as $col => $val) case 'maxdb':
{ if ($use_prepared_statement) break;
switch ($table_def['fd'][$col]['type']) // check if data contains any LONG columns
foreach($data as $col => $val)
{ {
case 'text': switch ($table_def['fd'][$col]['type'])
case 'longtext': {
case 'blob': case 'text':
$blobs2update[$col] = $data[$col]; case 'longtext':
unset($data[$col]); case 'blob':
break; $blobs2update[$col] = &$data[$col];
unset($data[$col]);
break;
}
} }
} break;
} }
$where = $this->column_data_implode(' AND ',$where,True,False,$table_def['fd']); $where = $this->column_data_implode(' AND ',$where,True,False,$table_def['fd']);
if (count($data)) if (count($data))
{ {
$sql = "UPDATE $table SET ". $inputarr = false;
$this->column_data_implode(',',$data,True,False,$table_def['fd']).' WHERE '.$where; if ($use_prepared_statement && $this->Link_ID->_bindInputArray) // eg. MaxDB
{
$ret = $this->query($sql,$line,$file); $this->Link_ID->Param(false); // reset param-counter
foreach($data as $col => $val)
{
$params[] = $this->name_quote($col).'='.$this->Link_ID->Param($col);
}
$sql = "UPDATE $table SET ".implode(',',$params).' WHERE '.$where;
// check if we already prepared that statement
if (!isset($this->prepared_sql[$sql]))
{
$this->prepared_sql[$sql] = $this->Link_ID->Prepare($sql);
}
$sql = $this->prepared_sql[$sql];
$inputarr = &$data;
}
else
{
$sql = "UPDATE $table SET ".
$this->column_data_implode(',',$data,True,False,$table_def['fd']).' WHERE '.$where;
}
$ret = $this->query($sql,$line,$file,0,-1,$inputarr);
if ($this->Debug) echo "<p>db::query('$sql',$line,$file) = '$ret'</p>\n"; if ($this->Debug) echo "<p>db::query('$sql',$line,$file) = '$ret'</p>\n";
} }
// if we have any blobs to update, we do so now // if we have any blobs to update, we do so now