Skip to content

Commit

Permalink
Merge pull request #48 from Icinga/support-dots-in-identifiers
Browse files Browse the repository at this point in the history
Quoter: Accept arrays of strings and quote parts as-is
  • Loading branch information
nilmerg authored Mar 21, 2022
2 parents a28c024 + 107abea commit 68ba15e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 10 deletions.
20 changes: 13 additions & 7 deletions src/Adapter/BaseAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,23 @@ public function setClientTimezone(Connection $db)
{
}

public function quoteIdentifier($identifier)
public function quoteIdentifier($identifiers)
{
if ($identifier === '*') {
return $identifier;
if (is_string($identifiers)) {
$identifiers = explode('.', $identifiers);
}

$identifier = str_replace($this->quoteCharacter[0], $this->escapeCharacter, $identifier);
foreach ($identifiers as $i => $identifier) {
if ($identifier === '*') {
continue;
}

$identifiers[$i] = $this->quoteCharacter[0]
. str_replace($this->quoteCharacter[0], $this->escapeCharacter, $identifier)
. $this->quoteCharacter[1];
}

return $this->quoteCharacter[0]
. str_replace('.', "{$this->quoteCharacter[0]}.{$this->quoteCharacter[1]}", $identifier)
. $this->quoteCharacter[1];
return implode('.', $identifiers);
}

protected function getTimezoneOffset()
Expand Down
10 changes: 7 additions & 3 deletions src/Contract/Quoter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
interface Quoter
{
/**
* Quote a string so that it can be safely used as table or column name, even if it is a reserved name
* Quote an identifier so that it can be safely used as table or column name, even if it is a reserved name
*
* If a string is passed that contains dots, the parts separated by them are quoted individually.
* (e.g. `myschema.mytable` turns into `"myschema"."mytable"`) If an array is passed, the entries
* are quoted as-is. (e.g. `[myschema.my, table]` turns into `"myschema.my"."table"`)
*
* The quote character depends on the underlying database adapter that is being used.
*
* @param string $identifier
* @param string|string[] $identifiers
*
* @return string
*/
public function quoteIdentifier($identifier);
public function quoteIdentifier($identifiers);
}
45 changes: 45 additions & 0 deletions tests/QuoterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace ipl\Tests\Sql;

class QuoterTest extends \PHPUnit\Framework\TestCase
{
protected $adapter;

protected function db()
{
if ($this->adapter === null) {
$this->adapter = new TestAdapter();
}

return $this->adapter;
}

/**
* @depends testSimpleNamesAreEscaped
* @depends testRelationPathsAreEscaped
* @depends testArrayValuesAreEscapedAsIs
*/
public function testWildcardsAreNotEscaped()
{
$this->assertEquals('*', $this->db()->quoteIdentifier('*'));
$this->assertEquals('*', $this->db()->quoteIdentifier(['*']));
$this->assertEquals('"foo".*', $this->db()->quoteIdentifier('foo.*'));
$this->assertEquals('"foo".*', $this->db()->quoteIdentifier(['foo', '*']));
}

public function testSimpleNamesAreEscaped()
{
$this->assertEquals('"foo"', $this->db()->quoteIdentifier('foo'));
}

public function testRelationPathsAreEscaped()
{
$this->assertEquals('"foo"."bar"."rab"."oof"', $this->db()->quoteIdentifier('foo.bar.rab.oof'));
}

public function testArrayValuesAreEscapedAsIs()
{
$this->assertEquals('"foo.bar"."rab.oof"', $this->db()->quoteIdentifier(['foo.bar', 'rab.oof']));
}
}

0 comments on commit 68ba15e

Please sign in to comment.