Follow-up to #2388255: (followup) Limit PDO MySQL to executing single statements if PHP supports it

Problem/Motivation

One of the reasons for the severity of https://www.drupal.org/SA-CORE-2014-005 was the fact the PDO MySQL allows multiple statements to be executed.

This affects all database drivers, not just MySQL

Proposed resolution

Check all SQL strings and throw an exception if a delimiter is present. This should not cause any problems if all user data is interpolated via placeholders.

Remaining tasks

User interface changes

n/a

API changes

better DB security

Comments

pwolanin’s picture

quick patch, to see if it breaks.

Status: Needs review » Needs work

The last submitted patch, 1: 2489672-1.patch, failed testing.

Status: Needs work » Needs review

mlhess queued 1: 2489672-1.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 1: 2489672-1.patch, failed testing.

mpdonadio’s picture

Assigned: Unassigned » mpdonadio

I am going take a stab at tracking down what is going wrong here.

mpdonadio’s picture

Status: Needs work » Needs review
StatusFileSize
new968 bytes
new794 bytes

Some CREATE TABLE commands have have semicolons in the COMMENT. Let's see if a full test run reveals any problems.

Status: Needs review » Needs work

The last submitted patch, 6: limit_all_db_drivers_to-2489672-6.patch, failed testing.

mpdonadio’s picture

Wuh? My install script and

php core/scripts/run-tests.sh --url http://localhost/drupal-8.0.x --all --verbose

is running just fine locally?

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new3.81 KB
new2.91 KB

Oh, yeah - I was thinking about semicolons in table comments at one point.

Maybe schema API can replace them when building the SQL?

I also found the sqlite driver was adding ; to schema creation statements. I think those can just be removed.

The difference you see with run-tests working locally is probably that the testbot uses the --sqlite option.

The interdiff here is to #1.

pwolanin’s picture

To avoid false positive perhaps we should rtirm() whitespace and ; in all queries?

Like: rtrim($query, "; \t\n\r\0\x0B") ?

Status: Needs review » Needs work

The last submitted patch, 9: 2489672-9.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new5.28 KB
new3.05 KB

Fixing up comment code also, and moved the delimiter check to a more central place that also catches most insert/update calls.

Status: Needs review » Needs work

The last submitted patch, 12: 2489672-12.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new6.54 KB
new1.26 KB

Simple unit test fix to account for replacing ; in comments.

Crell’s picture

  1. +++ b/core/lib/Drupal/Core/Database/Connection.php
    @@ -452,7 +452,7 @@ public function makeComment($comments) {
         // Flatten the array of comments.
    -    $comment = implode('; ', $comments);
    +    $comment = implode('. ', $comments);
    

    LOL. That is such a Drupal bug to have. I'm tempted to be a grammar pedant and ask if there's something other than periods that make sense, but...

  2. +++ b/core/lib/Drupal/Core/Database/Connection.php
    @@ -490,6 +490,8 @@ public function makeComment($comments) {
       protected function filterComment($comment = '') {
    +    // Remove semicolons to avoid triggering multi-statement check.
    +    $comment = strtr($comment, array(';' => '.'));
         return preg_replace('/(\/\*\s*)|(\s*\*\/)/', '', $comment);
       }
    

    This.

  3. +++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
    +++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
    @@ -456,7 +456,8 @@ public function prepareComment($comment, $length = NULL) {
    
    @@ -456,7 +456,8 @@ public function prepareComment($comment, $length = NULL) {
           // Add table prefixes before truncating.
           $comment = Unicode::truncate($this->connection->prefixTables($comment), $length, TRUE, TRUE);
         }
    -
    +    // Remove semicolons to avoid triggering multi-statement check.
    +    $comment = strtr($comment, array(';' => '.'));
         return $this->connection->quote($comment);
    

    And this. Seems redundant that we need to do it in both places, no?

mpdonadio’s picture

#15 2 and 3: one is for the COMMENT in the schema install (ie, the CREATE TABLE) and the other is for the comment() method on the query class.

pwolanin’s picture

@Crell - period seems the least silly option, but we can make them utf-8 emojis for all I care

[edit] but don't post emoji since they break core!

Crell’s picture

Status: Needs review » Reviewed & tested by the community

mpdonadio: Ah, OK. Silly DBTNG. Who wrote this thing?

Then I think it's fine. Thanks, pwolanin!

mpdonadio’s picture

Assigned: mpdonadio » Unassigned

Do we need to request a manual test run against PostgreSQL?

pwolanin’s picture

@mpdonadio - yes, that would be a good idea

Crell’s picture

Both PostgreSQL and SQLite. Is there a doc page somewhere that explains how we do that now? (It's kinda sad that I don't know that, being DB maintainer and all...)

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php
@@ -254,11 +254,11 @@ public function providerMakeComments() {
-        '/* Exploit * / DROP TABLE node; -- */ ',
+        '/* Exploit * / DROP TABLE node. -- */ ',
...
       array(
-        '/* Exploit DROP TABLE node; --; another comment */ ',
+        '/* Exploit DROP TABLE node. --. another comment */ ',

@@ -286,8 +286,8 @@ public function testMakeComments($expected, $comment_array) {
-      array('Exploit * / DROP TABLE node; --', 'Exploit * / DROP TABLE node; --'),
-      array('Exploit DROP TABLE node; --', 'Exploit */ DROP TABLE node; --'),
+      array('Exploit * / DROP TABLE node. --', 'Exploit * / DROP TABLE node; --'),
+      array('Exploit DROP TABLE node. --', 'Exploit */ DROP TABLE node; --'),

This looks weird - should we be testing that the exploit protection works here instead?

Running the Database group of test. SQLite is fine with this patch... Postgres is not.

Before patch

Test summary
------------

Drupal\system\Tests\Database\AlterTest                        34 passes
Drupal\system\Tests\Database\BasicSyntaxTest                  23 passes
Drupal\system\Tests\Database\CaseSensitivityTest               4 passes
Drupal\system\Tests\Database\ConnectionTest                   24 passes   1 fails
Drupal\system\Tests\Database\ConnectionUnitTest                7 passes
Drupal\system\Tests\Database\DatabaseExceptionWrapperTest      2 passes
Drupal\system\Tests\Database\DeleteTruncateTest               12 passes
Drupal\system\Tests\Database\FetchTest                        41 passes
Drupal\system\Tests\Database\InsertDefaultsTest               10 passes
Drupal\system\Tests\Database\InsertLobTest                     7 passes
Drupal\system\Tests\Database\InsertTest                       30 passes
Drupal\system\Tests\Database\InvalidDataTest                   4 passes
Drupal\system\Tests\Database\LoggingTest                      24 passes
Drupal\system\Tests\Database\MergeTest                        52 passes
Drupal\system\Tests\Database\NextIdTest                        4 passes
Drupal\system\Tests\Database\QueryTest                        15 passes
Drupal\system\Tests\Database\RangeQueryTest                    4 passes
Drupal\system\Tests\Database\RegressionTest                   15 passes
Drupal\system\Tests\Database\SchemaTest                      748 passes
Drupal\system\Tests\Database\SelectCloneTest                   4 passes
Drupal\system\Tests\Database\SelectComplexTest                94 passes
Drupal\system\Tests\Database\SelectOrderedTest                17 passes
Drupal\system\Tests\Database\SelectPagerDefaultTest           22 passes
Drupal\system\Tests\Database\SelectSubqueryTest               19 passes
Drupal\system\Tests\Database\SelectTableSortDefaultTest       32 passes
Drupal\system\Tests\Database\SelectTest                      106 passes
Drupal\system\Tests\Database\SerializeQueryTest                3 passes
Drupal\system\Tests\Database\TaggingTest                      28 passes
Drupal\system\Tests\Database\TemporaryQueryTest                7 passes
Drupal\system\Tests\Database\TransactionTest                  55 passes
Drupal\system\Tests\Database\UpdateComplexTest                35 passes
Drupal\system\Tests\Database\UpdateLobTest                     7 passes
Drupal\system\Tests\Database\UpdateTest                       35 passes

After patch

Test summary
------------

Drupal\system\Tests\Database\AlterTest                        34 passes
Drupal\system\Tests\Database\BasicSyntaxTest                  23 passes
Drupal\system\Tests\Database\CaseSensitivityTest               4 passes
Drupal\system\Tests\Database\ConnectionTest                   25 passes
Drupal\system\Tests\Database\ConnectionUnitTest                7 passes
Drupal\system\Tests\Database\DatabaseExceptionWrapperTest      2 passes
Drupal\system\Tests\Database\DeleteTruncateTest               12 passes
Drupal\system\Tests\Database\FetchTest                        41 passes
Drupal\system\Tests\Database\InsertDefaultsTest               10 passes
Drupal\system\Tests\Database\InsertLobTest                     7 passes
Drupal\system\Tests\Database\InsertTest                       30 passes
Drupal\system\Tests\Database\InvalidDataTest                   4 passes
Drupal\system\Tests\Database\LoggingTest                      24 passes
Drupal\system\Tests\Database\MergeTest                        52 passes
Drupal\system\Tests\Database\NextIdTest                        4 passes
Drupal\system\Tests\Database\QueryTest                        15 passes
Drupal\system\Tests\Database\RangeQueryTest                    4 passes
Drupal\system\Tests\Database\RegressionTest                   15 passes
Drupal\system\Tests\Database\SchemaTest                      748 passes
Drupal\system\Tests\Database\SelectCloneTest                   4 passes
Drupal\system\Tests\Database\SelectComplexTest                94 passes
Drupal\system\Tests\Database\SelectOrderedTest                17 passes
Drupal\system\Tests\Database\SelectPagerDefaultTest            0 passes             1 exceptions
Drupal\system\Tests\Database\SelectSubqueryTest               19 passes
Drupal\system\Tests\Database\SelectTableSortDefaultTest        0 passes             1 exceptions
Drupal\system\Tests\Database\SelectTest                      106 passes
Drupal\system\Tests\Database\SerializeQueryTest                3 passes
Drupal\system\Tests\Database\TaggingTest                      28 passes
Drupal\system\Tests\Database\TemporaryQueryTest                0 passes             1 exceptions
Drupal\system\Tests\Database\TransactionTest                  55 passes
Drupal\system\Tests\Database\UpdateComplexTest                35 passes
Drupal\system\Tests\Database\UpdateLobTest                     7 passes
Drupal\system\Tests\Database\UpdateTest                       35 passes

To run tests with postgres just pass run-tests.sh a valid postgres database connection url.

Isn't this change adding extra code for no reason now we've gone for #2388255: (followup) Limit PDO MySQL to executing single statements if PHP supports it and doesn't Postgres have something similar to protect a user from running mulitple sql statements?

Crell’s picture

The PDO single-statement flag was only added in a super-recent version of PHP, so there are still a lot of users that won't have that check. This is an extra check for users that don't have that flag. I cannot speak to Postgres', as I've never used it for more than 10 minutes.

pwolanin’s picture

I don't think Postgres has any flag to limit to single statements, so the idea here is to protect Postgres and any other SQL back-end from typical SQL injection attacks (basically adding a 2nd statement onto a select)

bzrudi71’s picture

@pwolanin, PostgreSQL PDO limits to single statements by default, but we explicit allow multiple statements by enabling emulated prepares ;)

pwolanin’s picture

right - so it's not clear that for a performance we can make postgres or mysql use native prepares (an extra round trip to the server for every query - which is a lot if you DB server is over a network connection with even just 1-2 ms latency).

Ideally we can backport this change to 7 also since we won't ever switch to native prepares there.

pwolanin’s picture

do we have a postgres testbot now?

bzrudi71’s picture

@pwolanin yes, you have to re-upload your patch again to enable PG testing. Unfortunately there are still many random exceptions with PG, all related to some kind of already installed exceptions that we need to fix first before getting meaningfully results ;)

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new6.54 KB

re-uplading and setting to NR to see if I can get the other tests to run

pwolanin’s picture

StatusFileSize
new6.54 KB

re-uploading - looks like sqlite errors mostly went away

pwolanin’s picture

StatusFileSize
new6.54 KB

Re-roll against HEAD

pwolanin’s picture

StatusFileSize
new6.54 KB

trying again for a multi-SQL test run

pwolanin’s picture

StatusFileSize
new6.7 KB

Here's a re-roll for conflicts.

pwolanin’s picture

StatusFileSize
new7.85 KB
new1.92 KB

Here's a dumb fix for postgres fails during setup.

Needs to be cleaner, but at least we can see if the basic approach is enough.

The last submitted patch, 34: 2489672-34.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 35: 2489672-35.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new15.64 KB
new12.62 KB

ok, talked to dawehner about this and he had a better suggestion of putting a flag in the query options.

Also fixes some tests of query comments where I didn't make the right changes in the last patch.

dawehner’s picture

+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -529,7 +534,8 @@ public function makeComment($comments) {
-    return strtr($comment, ['*' => ' * ']);
+    // Change semicolons to period to avoid triggering multi-statement check.
+    return strtr($comment, ['*' => ' * ', ';' => '.']);

+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
@@ -540,7 +540,8 @@ public function prepareComment($comment, $length = NULL) {
+    // Remove semicolons to avoid triggering multi-statement check.
+    $comment = strtr($comment, array(';' => '.'));

Is there any particular reason why we don't use str_replace?

pwolanin’s picture

@dawehner - in some benchmarks strtr is faster, and I think it's also easier to understand since it's what we used inside, t(), etc.

The pgsql results look like less fails than HEAD, strangely. At the least, not causing the total failure we had earlier.

Crell’s picture

The flag makes sense here, I think. Nice work. A minor nit, but otherwise I'm happy with the latest patch. (I don't know what our postgres policy is this week on whether this is RTBCable or not.)

  1. +++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
    @@ -540,7 +540,8 @@ public function prepareComment($comment, $length = NULL) {
    +    // Remove semicolons to avoid triggering multi-statement check.
    +    $comment = strtr($comment, array(';' => '.'));
    

    New-style arrays, please.

  2. +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Install/Tasks.php
    @@ -192,28 +192,40 @@ function initializeDatabase() {
    +      $connection = Database::getConnection();
           // Create functions.
    -      db_query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric) RETURNS numeric AS
    +      $connection->query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric) RETURNS numeric AS
    

    Thank you! :-)

pwolanin’s picture

StatusFileSize
new15.64 KB
new571 bytes

fiasco looked at the patch, but I'll ping him to leave a comment also.

greggles’s picture

I picked some nits.

  1. +++ b/core/lib/Drupal/Core/Database/Connection.php
    @@ -593,6 +599,15 @@ public function query($query, array $args = array(), $options = array()) {
    +        // allowed unless the option is set.  This is needed for special cases
    

    The word "This" feels ambiguous. How about "Semicolons are needed..."

  2. +++ b/core/lib/Drupal/Core/Database/Connection.php
    @@ -593,6 +599,15 @@ public function query($query, array $args = array(), $options = array()) {
    +          throw new \InvalidArgumentException('; is not supported in SQL strings.  Use only one statement at a time');
    

    Missing a closing period on the second sentence.

  3. +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Install/Tasks.php
    @@ -192,28 +192,40 @@ function initializeDatabase() {
    +    // During tasks we may need to run complex SQL like creating functions
    

    This sentence feels incomplete and disjointed from the previous paragraph.

pwolanin’s picture

StatusFileSize
new15.43 KB
new2.25 KB

I'm not able to reproduce some of the postgres fails locally using vagrant + PHP 5.6.12 + pgsql 9.3

e.g. these 3 pass for me:

Drupal\aggregator\Tests\AggregatorAdminTest
Drupal\system\Tests\Theme\EntityFilteringThemeTest
Drupal\system\Tests\System\FloodTest

Patch fixes code comments up for nits.

Crell’s picture

Status: Needs review » Reviewed & tested by the community

Per #42 this is probably as much of a Postgres review as we're going to get, so let's move on.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 44: 2489672-44.patch, failed testing.

bzrudi71’s picture

Status: Needs work » Needs review

@crell since we have a green testbot (since some hours) let's do another retest to make sure everything works as expected before setting to RTBC.

bzrudi71’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll
nikolay shapovalov’s picture

Assigned: Unassigned » nikolay shapovalov

zniki.ru queued 44: 2489672-44.patch for re-testing.

The last submitted patch, 44: 2489672-44.patch, failed testing.

nikolay shapovalov’s picture

Status: Needs work » Needs review
StatusFileSize
new15.07 KB

Rerolled.

nikolay shapovalov’s picture

Assigned: nikolay shapovalov » Unassigned
Issue tags: -Needs reroll
pwolanin’s picture

Status: Needs review » Needs work

So, looks like there are new or more postgres fails to fix.

pwolanin’s picture

StatusFileSize
new15.07 KB

re-posting the last patch to check currrent pgsql fails.

pwolanin’s picture

Status: Needs work » Needs review
bzrudi71’s picture

Looking at the fails I have to wonder. They are about creating the GREATEST and CONCAT functions, but we removed them (because obsolete in PostgreSQL > 9.1) in #2552769: Remove outdated custom functions for greatest() and concat() ;)

tstoeckler’s picture

Status: Needs review » Needs work

This seems to revert #2552769: Remove outdated custom functions for greatest() and concat(), probably a merge error or something. Marking needs work for that.

+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -239,6 +239,10 @@ public function destroy() {
+   * - allow_delimiter_in_query: By default, queries which have the ; delimiter
+   *   any place in them will cause an exception. In rare cases, such as

Should we document *why* this is the case or is that obvious? (I'm genuinely asking, I thought about this myself and am not sure.)

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new13.29 KB
new3.77 KB

Ok, taking those out, let's see if the tests are better.

Status: Needs review » Needs work

The last submitted patch, 60: 2489672-60.patch, failed testing.

pwolanin queued 60: 2489672-60.patch for re-testing.

pwolanin’s picture

Status: Needs work » Needs review

ok, I think those were sporadic fails.

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC, looks great to me!

alexpott’s picture

Title: Limit all DB drivers to executing single statements by checking for deleimiter » Limit all DB drivers to executing single statements by checking for delimiter

Fixing title

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 60: 2489672-60.patch, failed testing.

dawehner queued 60: 2489672-60.patch for re-testing.

pwolanin’s picture

Status: Needs work » Reviewed & tested by the community

sporadic fail apparently.

effulgentsia’s picture

StatusFileSize
new13.29 KB

I'm having a hard time interpreting the conflicting DrupalCI results in #60, so reuploading that patch to get fresh, uncluttered, results.

effulgentsia’s picture

Is that SQLite failure expected? I notice that #60 didn't have any SQLite test running?

effulgentsia’s picture

Status: Reviewed & tested by the community » Needs review

Per #70.

pwolanin’s picture

The failure is Value 'Basic page' is equal to value 'Article'

If it's not something sporadic, then it must be a HEAD regression. It can't be related to this patch, which would cause failures by throwing exceptions.

Let me re-upload the patch to get fresh tests.

pwolanin’s picture

StatusFileSize
new13.29 KB
pwolanin’s picture

The node test fail from above is already in 8.0.x https://www.drupal.org/pift-ci-job/37937

pwolanin queued 73: 2489672-60_repost.patch for re-testing.

pwolanin’s picture

Status: Needs review » Reviewed & tested by the community

one of the test fails in in 8.0.x: #2573289: Core NodeAdminTest test failing on sqlite due to unspecified node ordering

I don't see the other test fail locally. Putting back to RTBC since I think this was just something with the bot

effulgentsia’s picture

effulgentsia’s picture

Adding credit to @bzrudi71 and @Crell for multiple reviews and investigations into related issues.

effulgentsia’s picture

Removing credit from myself. I only re-uploaded existing patches, didn't contribute anything significant of my own.

  • effulgentsia committed 596b69f on 8.0.x
    Issue #2489672 by pwolanin, mpdonadio, zniki.ru, bzrudi71, Crell: Limit...
effulgentsia’s picture

Title: Limit all DB drivers to executing single statements by checking for delimiter » [needs change record] Limit all DB drivers to executing single statements by checking for delimiter
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record

I like how this patch hardens Drupal's Database API for users without a database engine/configuration that does it at that layer. Also, this was RTBC for over a week between #68 and #69 without anyone raising a concern with doing this. I also reviewed the patch myself and no concerns jumped out at me. Therefore, committed and pushed to 8.0.x.

I think we could use a change record for module developers who create SQL functions, like the below, so "needs work" for that.

+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -239,6 +239,12 @@ public function destroy() {
+   *   additional queries (such as inserting new user accounts). In rare cases,
+   *   such as creating an SQL function, a ; is needed and can be allowed by
+   *   changing this option to TRUE.
...
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Install/Tasks.php
@@ -250,18 +250,23 @@ function initializeDatabase() {
-      if (!db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'")->fetchField()) {
-        db_query('CREATE OR REPLACE FUNCTION "rand"() RETURNS float AS
+      if (!$connection->query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'")->fetchField()) {
+        $connection->query('CREATE OR REPLACE FUNCTION "rand"() RETURNS float AS
           \'SELECT random();\'
-          LANGUAGE \'sql\''
+          LANGUAGE \'sql\'',
+          [],
+          [ 'allow_delimiter_in_query' => TRUE ]
         );
pwolanin’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record

added draft change record

larowlan’s picture

Title: [needs change record] Limit all DB drivers to executing single statements by checking for delimiter » Limit all DB drivers to executing single statements by checking for delimiter
Status: Needs review » Reviewed & tested by the community

Change record looks good to me - looking forward to this in core

effulgentsia’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)
Issue tags: -Needs backport to D7

Thanks. I published the CR, so moving this to the 7.x queue.

The last submitted patch, 60: 2489672-60.patch, failed testing.

  • effulgentsia committed 596b69f on 8.1.x
    Issue #2489672 by pwolanin, mpdonadio, zniki.ru, bzrudi71, Crell: Limit...
stefan.r’s picture

Just bumping this as this would be good to get into 7.x

  • effulgentsia committed 596b69f on 8.3.x
    Issue #2489672 by pwolanin, mpdonadio, zniki.ru, bzrudi71, Crell: Limit...

  • effulgentsia committed 596b69f on 8.3.x
    Issue #2489672 by pwolanin, mpdonadio, zniki.ru, bzrudi71, Crell: Limit...
fabianx’s picture

Issue tags: +Drupal bugfix target

  • effulgentsia committed 596b69f on 8.4.x
    Issue #2489672 by pwolanin, mpdonadio, zniki.ru, bzrudi71, Crell: Limit...

  • effulgentsia committed 596b69f on 8.4.x
    Issue #2489672 by pwolanin, mpdonadio, zniki.ru, bzrudi71, Crell: Limit...
mlncn’s picture

Regarding Drupal 8. Warning, this blows up a statement like:

\Drupal::database()->query('SELECT n.nid FROM {node} as n LEFT JOIN {key_value} as kv ON n.nid=kv.name WHERE kv.collection="pathauto_state.node" AND kv.value="i:0;"')

NOTICE: PHP message: Uncaught PHP Exception PDOException: "SQLSTATE[HY093]: Invalid parameter number: no parameters were bound" at /var/www/html/web/core/lib/Drupal/Core/Database/Statement.php

And while that's easy enough to work around by adding placeholders even though the offending query parameters aren't based on user input:

$nids = \Drupal::database()->query("SELECT n.nid FROM {node} as n LEFT JOIN {key_value} as kv ON n.nid=kv.name WHERE kv.collection='pathauto_state.node' AND kv.value=:val",
  [':val' => 'i:0;'])->fetchCol(); 

If you're trying to do an UPDATE query with a join i think you're straight out of luck.

Status: Patch (to be ported) » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.

quietone’s picture

Version: 7.x-dev » 8.0.x-dev
Status: Closed (outdated) » Fixed

This was committed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

xjm’s picture

Restoring credits.