Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Untangles the control of the casing and quoting of columns #864

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 18 additions & 12 deletions adodb-active-record.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -1123,8 +1123,9 @@ function GetAttributeNames()
/**
* Quotes the table, column and field names.
*
* This honours the internal {@see $_quoteNames} property, which overrides
* the global $ADODB_QUOTE_FIELDNAMES directive.
* This uses the standard _adodb_quote_fieldname() settings, and ignores
* the internal {@see $_quoteNames} property, and the global
* $ADODB_QUOTE_FIELDNAMES directive.
*
* @param ADOConnection $db The database connection
* @param string $name The table or column name to quote
Expand All @@ -1133,16 +1134,21 @@ function GetAttributeNames()
*/
private function nameQuoter($db, $name)
{
global $ADODB_QUOTE_FIELDNAMES;

$save = $ADODB_QUOTE_FIELDNAMES;
$ADODB_QUOTE_FIELDNAMES = $this->_quoteNames;

$string = _adodb_quote_fieldname($db, $name);

$ADODB_QUOTE_FIELDNAMES = $save;

return $string;
if (isset($this->_quoteNames) && $this->_quoteNames && $db->debug)
{
$msg = "
Warning: The class variable '_quoteNames' has been deprecated and will be
removed in the next release. Control field casing and quoting using
ADOConnection::setQuoteStyle() and ADOConnection::setElementCase()
To match your setting, both quoteStyle and elementCase were set to 1
To control this manually, remove your _quoteNames setting";
ADOConnection::outp($msg);
$db->setElementCase(1);
$db->setQuoteStyle(1);

}

return _adodb_quote_fieldname($db, $name);
}

};
Expand Down
48 changes: 29 additions & 19 deletions adodb-datadict.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,17 @@ function metaType($t,$len=-1,$fieldobj=false)
return $this->connection->metaType($t,$len,$fieldobj);
}

/**
* A legacy wrapper for the field name quoting system.
* Now calls the standard _adodb_quote_fieldname method and
* respects the quote style and casing set there. Ignores
* The active record settings for this
*
* @param string $name The fieldname
* @param bool $allowBrackets (ignored)
*
* @return string The processed name
*/
function nameQuote($name = NULL,$allowBrackets=false)
{
if (!is_string($name)) {
Expand All @@ -362,29 +373,28 @@ function nameQuote($name = NULL,$allowBrackets=false)
return $name;
}

$quote = $this->connection->nameQuote;

// if name is of the form `name`, quote it
if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
return $quote . $matches[1] . $quote;
}

// if name contains special characters, quote it
$regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;

if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
return $quote . $name . $quote;
}

return $name;
return _adodb_quote_fieldname($this->connection,$name);

}

/**
* A legacy wrapper for the table name quoting system.
* Now calls the standard _adodb_quote_fieldname method and
* respects the quote style and casing set there. Ignores
* The active record settings for this
*
* @param string $name The table name
*
* @return string The processed name
*/
function tableName($name)
{
if ( $this->schema ) {
return $this->nameQuote($this->schema) .'.'. $this->nameQuote($name);
}
return $this->nameQuote($name);

if ($this->schema)
$name = sprintf('%s.%s', $this->schema,$name);

return _adodb_quote_fieldname($this->connection,$name);

}

// Executes the sql array returned by getTableSQL and getIndexSQL
Expand Down
122 changes: 80 additions & 42 deletions adodb-lib.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ function adodb_transpose(&$arr, &$newarr, &$hdr, $fobjs)
function _adodb_replace($zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
{
// Add Quote around table name to support use of spaces / reserved keywords
$table=sprintf('%s%s%s', $zthis->nameQuote,$table,$zthis->nameQuote);

$table = _adodb_quote_fieldname($zthis,$table);

if (count($fieldArray) == 0) return 0;

Expand All @@ -148,18 +149,21 @@ function _adodb_replace($zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_a
$v = $zthis->qstr($v);
$fieldArray[$k] = $v;
}
if (in_array($k,$keyCol)) continue; // skip UPDATE if is key
if (in_array($k,$keyCol))
continue; // skip UPDATE if is key

// Add Quote around column name to support use of spaces / reserved keywords
$uSet .= sprintf(',%s%s%s=%s',$zthis->nameQuote,$k,$zthis->nameQuote,$v);
$element = _adodb_quote_fieldname($zthis,$k);
$uSet .= sprintf(',%s=%s',$element, $v);
}
$uSet = ltrim($uSet, ',');

// Add Quote around column name in where clause
$where = '';
foreach ($keyCol as $v) {
if (isset($fieldArray[$v])) {
$where .= sprintf(' and %s%s%s=%s ', $zthis->nameQuote,$v,$zthis->nameQuote,$fieldArray[$v]);
$element = _adodb_quote_fieldname($zthis,$v);
$where .= sprintf(' AND %s=%s ', $element,$fieldArray[$v]);
}
}
if ($where) {
Expand Down Expand Up @@ -187,16 +191,25 @@ function _adodb_replace($zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_a
return 0;
}

$iCols = $iVals = '';
foreach($fieldArray as $k => $v) {
if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
$iColArray = $iValArray = array();


// Remove autp-increment columns and quote any columns
// either by defined setting or if the column name contains
// spaces
foreach($fieldArray as $k => $v)
{
if ($has_autoinc && in_array($k,$keyCol))
continue; // skip autoinc col

// Add Quote around Column Name
$iCols .= sprintf(',%s%s%s',$zthis->nameQuote,$k,$zthis->nameQuote);
$iVals .= ",$v";
// Add Quote around Column Name
$iColArray[] = _adodb_quote_fieldname($zthis,$k);
$iValArray[] = $v;
}
$iCols = ltrim($iCols, ',');
$iVals = ltrim($iVals, ',');

$iCols = implode(',',$iColArray);
$iVals = implode(',',$iValArray);


$insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
$rs = $zthis->Execute($insert);
Expand Down Expand Up @@ -663,9 +676,7 @@ function _adodb_pageexecute_no_last_page($zthis, $sql, $nrows, $page, $inputarr=
}

/**
* Performs case conversion and quoting of the given field name.
*
* See Global variable $ADODB_QUOTE_FIELDNAMES.
* Performs optional case conversion and quoting of the given field name.
*
* @param ADOConnection $zthis
* @param string $fieldName
Expand All @@ -674,34 +685,57 @@ function _adodb_pageexecute_no_last_page($zthis, $sql, $nrows, $page, $inputarr=
*/
function _adodb_quote_fieldname($zthis, $fieldName)
{
global $ADODB_QUOTE_FIELDNAMES;

// Case conversion - defaults to UPPER
$case = is_bool($ADODB_QUOTE_FIELDNAMES) ? 'UPPER' : $ADODB_QUOTE_FIELDNAMES;
switch ($case) {
case 'LOWER':
$fieldName = strtolower($fieldName);
break;
case 'NATIVE':
// Do nothing
break;
case 'UPPER':
case 'BRACKETS':
default:
$fieldName = strtoupper($fieldName);
break;


$containsSpecialCharacters = false;

//If the field name is already quoted, we need to remove it
$quoteStyles = $zthis->getQuoteStyles();

$prefix = implode('|',array_filter(array_column($quoteStyles,0)));
$suffix = implode('|',array_filter(array_column($quoteStyles,1)));

//Is the field already quoted

if (preg_match('/^[' . $prefix . '].*[' . $suffix . ']$/' , $fieldName))
{
// Already quoted, remove it
$fieldName = substr($fieldName,1,strlen($fieldName) - 2);

}

// if name contains anything but this, quote it
$fieldRegex = '/^[a-zA-Z0-9_]+$/';

if (!preg_match($fieldRegex,$fieldName))
// Test also absorbs spaces
$containsSpecialCharacters = true;


// Field Case conversion - defaults to unchanged

switch ($zthis->getElementCase()) {
case $zthis::ELEMENTCASE_LOWER:
$fieldName = strtolower($fieldName);
break;

case $zthis::ELEMENTCASE_UPPER:
$fieldName = strtoupper($fieldName);
break;
default:
case $zthis::ELEMENTCASE_DEFAULT:
// Do nothing
}

list ($elementQuotes,$fallbackQuotes) = $zthis->getElementQuotes();

// Quote field if requested, or necessary (field contains space)
if ($ADODB_QUOTE_FIELDNAMES || strpos($fieldName, ' ') !== false ) {
if ($ADODB_QUOTE_FIELDNAMES === 'BRACKETS') {
return $zthis->leftBracket . $fieldName . $zthis->rightBracket;
} else {
return $zthis->nameQuote . $fieldName . $zthis->nameQuote;
}
} else {
return $fieldName;
}
if ($containsSpecialCharacters) {
return sprintf('%s%s%s',$fallbackQuotes[0],$fieldName,$fallbackQuotes[1]);
}

return sprintf('%s%s%s',$elementQuotes[0],$fieldName,$elementQuotes[1]);

}

function _adodb_getupdatesql(&$zthis, $rs, $arrFields, $forceUpdate=false, $force=2)
Expand Down Expand Up @@ -822,6 +856,8 @@ function _adodb_getupdatesql(&$zthis, $rs, $arrFields, $forceUpdate=false, $forc
preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
$tableName = $tableName[1];
}

$tableName = _adodb_quote_fieldname($zthis,$tableName);

// Get the full where clause excluding the word "WHERE" from the existing query.
preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
Expand Down Expand Up @@ -888,7 +924,6 @@ function _adodb_getinsertsql(&$zthis, $rs, $arrFields, $force=2)
//ok we have a table name
//try and get the column info ourself.
$tableName = $rs;

//we need an object for the recordSet
//because we have to call MetaType.
//php can't do a $rsclass::MetaType()
Expand Down Expand Up @@ -1001,12 +1036,15 @@ function _adodb_getinsertsql(&$zthis, $rs, $arrFields, $force=2)

// Get the table name from the existing query.
if (!$tableName) {
if (!empty($rs->tableName)) $tableName = $rs->tableName;
if (!empty($rs->tableName))
$tableName = $rs->tableName;
else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName))
$tableName = $tableName[1];
else
return false;
}

$tableName = _adodb_quote_fieldname($zthis,$tableName);

// Strip off the comma and space on the end of both the fields
// and their values.
Expand Down