Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
f8604e14
Commit
f8604e14
authored
Jan 17, 2013
by
Guilherme Blanco
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #113 from avit/master
Fixed SQL placeholder parsing
parents
328d8a53
153b752f
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
43 additions
and
18 deletions
+43
-18
SQLParserUtils.php
lib/Doctrine/DBAL/SQLParserUtils.php
+35
-18
SQLParserUtilsTest.php
tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php
+8
-0
No files found.
lib/Doctrine/DBAL/SQLParserUtils.php
View file @
f8604e14
...
...
@@ -32,6 +32,13 @@ use Doctrine\DBAL\Connection;
*/
class
SQLParserUtils
{
const
POSITIONAL_TOKEN
=
'\?'
;
const
NAMED_TOKEN
=
':[a-zA-Z_][a-zA-Z0-9_]*'
;
// Quote characters within string literals can be preceded by a backslash.
const
ESCAPED_SINGLE_QUOTED_TEXT
=
"'(?:[^'
\\\\
]|
\\\\
'|
\\\\\\\\
)*'"
;
const
ESCAPED_DOUBLE_QUOTED_TEXT
=
'"(?:[^"\\\\]|\\\\"|\\\\\\\\)*"'
;
/**
* Get an array of the placeholders in an sql statements as keys and their positions in the query string.
*
...
...
@@ -49,27 +56,18 @@ class SQLParserUtils
return
array
();
}
$count
=
0
;
$inLiteral
=
false
;
// a valid query never starts with quotes
$stmtLen
=
strlen
(
$statement
);
$token
=
(
$isPositional
)
?
self
::
POSITIONAL_TOKEN
:
self
::
NAMED_TOKEN
;
$paramMap
=
array
();
for
(
$i
=
0
;
$i
<
$stmtLen
;
$i
++
)
{
if
(
$statement
[
$i
]
==
$match
&&
!
$inLiteral
&&
(
$isPositional
||
$statement
[
$i
+
1
]
!=
'='
))
{
// real positional parameter detected
foreach
(
self
::
getUnquotedStatementFragments
(
$statement
)
as
$fragment
)
{
preg_match_all
(
"/
$token
/"
,
$fragment
[
0
],
$matches
,
PREG_OFFSET_CAPTURE
);
foreach
(
$matches
[
0
]
as
$placeholder
)
{
if
(
$isPositional
)
{
$paramMap
[
$count
]
=
$i
;
$paramMap
[
]
=
$placeholder
[
1
]
+
$fragment
[
1
]
;
}
else
{
$name
=
""
;
// TODO: Something faster/better to match this than regex?
for
(
$j
=
$i
+
1
;
(
$j
<
$stmtLen
&&
preg_match
(
'(([a-zA-Z0-9_]{1}))'
,
$statement
[
$j
]));
$j
++
)
{
$name
.=
$statement
[
$j
];
}
$paramMap
[
$i
]
=
$name
;
// named parameters can be duplicated!
$i
=
$j
;
$pos
=
$placeholder
[
1
]
+
$fragment
[
1
];
$paramMap
[
$pos
]
=
substr
(
$placeholder
[
0
],
1
,
strlen
(
$placeholder
[
0
]));
}
++
$count
;
}
else
if
(
$statement
[
$i
]
==
"'"
||
$statement
[
$i
]
==
'"'
)
{
$inLiteral
=
!
$inLiteral
;
// switch state!
}
}
...
...
@@ -180,4 +178,23 @@ class SQLParserUtils
return
array
(
$query
,
$paramsOrd
,
$typesOrd
);
}
/**
* Slice the SQL statement around pairs of quotes and
* return string fragments of SQL outside of quoted literals.
* Each fragment is captured as a 2-element array:
*
* 0 => matched fragment string,
* 1 => offset of fragment in $statement
*
* @param string $statement
* @return array
*/
static
private
function
getUnquotedStatementFragments
(
$statement
)
{
$literal
=
self
::
ESCAPED_SINGLE_QUOTED_TEXT
.
'|'
.
self
::
ESCAPED_DOUBLE_QUOTED_TEXT
;
preg_match_all
(
"/([^'
\"
]+)(?:
$literal
)?/s"
,
$statement
,
$fragments
,
PREG_OFFSET_CAPTURE
);
return
$fragments
[
1
];
}
}
\ No newline at end of file
tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php
View file @
f8604e14
...
...
@@ -28,6 +28,13 @@ class SQLParserUtilsTest extends \Doctrine\Tests\DbalTestCase
array
(
"SELECT '?' FROM foo"
,
true
,
array
()),
array
(
'SELECT "?" FROM foo WHERE bar = ?'
,
true
,
array
(
32
)),
array
(
"SELECT '?' FROM foo WHERE bar = ?"
,
true
,
array
(
32
)),
array
(
<<<'SQLDATA'
SELECT * FROM foo WHERE bar = 'it\'s a trap? \\' OR bar = ?
AND baz = "\"quote\" me on it? \\" OR baz = ?
SQLDATA
,
true
,
array
(
58
,
104
)
),
// named
array
(
'SELECT :foo FROM :bar'
,
false
,
array
(
7
=>
'foo'
,
17
=>
'bar'
)),
...
...
@@ -37,6 +44,7 @@ class SQLParserUtilsTest extends \Doctrine\Tests\DbalTestCase
array
(
'SELECT :foo_id'
,
false
,
array
(
7
=>
'foo_id'
)),
// Ticket DBAL-231
array
(
'SELECT @rank := 1'
,
false
,
array
()),
// Ticket DBAL-398
array
(
'SELECT @rank := 1 AS rank, :foo AS foo FROM :bar'
,
false
,
array
(
27
=>
'foo'
,
44
=>
'bar'
)),
// Ticket DBAL-398
array
(
'SELECT * FROM Foo WHERE bar > :start_date AND baz > :start_date'
,
false
,
array
(
30
=>
'start_date'
,
52
=>
'start_date'
))
// Ticket GH-113
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment