Problem/Motivation

PDO driver has a limit to the number of named arguments you can use.
This varies by DB driver.
When using operations that perform bulk actions on entities, such as deleting multiple entities, it is possible to hit this limit.

Steps to reproduce

Proposed resolution

Document that such operations should be performed in chunks.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Original report

API page: http://api.drupal.org/api/drupal/modules--node--node.module/function/nod...

Describe the problem you have found:

It should be noted that the argument array to node_delete_multiple() should be limited in size to avoid a PDO error like #1210092: PDOException: SQLSTATE[HY000]: General error: 1 too many SQL variables: SELECT t.* FROM {field_data_body} t WHERE (entity_type =

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pillarsdotnet’s picture

Status: Active » Needs review
FileSize
2.32 KB
pillarsdotnet’s picture

Version: 7.x-dev » 8.x-dev
Issue tags: +Needs backport to D7
FileSize
2.32 KB

The same docs change, rolled for 8.x

pillarsdotnet’s picture

Title: Documentation problem with node_delete_multiple » Note limited argument length in node_delete_multiple(), node_load_multiple(), and buildQuery() functions.
jhodgdon’s picture

What exactly is the limit? Adding this documentation seems like a reasonable idea, but maybe it should give me some idea what the limit is, or what it depends on?

pillarsdotnet’s picture

I imagine that the limit is dependent on the database driver and/or configuration. In my testing configuration (PHP 5.5.0 with memory_limit set to 256M, PDO/sqlite3 database), 2000 is clearly too high.

I didn't try to find exactly what number breaks the query in my configuration, let alone under a broad range of databases and memory limit configurations.

jhodgdon’s picture

Hm. Can we provide any guidance at all then?

pillarsdotnet’s picture

Hm. Can we provide any guidance at all then?

Not without extensive testing that I frankly am not interested in doing. For all I know, it's a fundamental hard-coded limit of PDO and not dependent on database/driver/config at all. If so, then our function should be rewritten to enforce the limits of the language we are using.

salvis’s picture

You've identified PDO as the bottleneck for the number of values inside IN()? Good!

pillarsdotnet’s picture

You've identified PDO as the bottleneck for the number of values inside IN()? Good!

No I have not identified the bottleneck. Nor am I interested in doing so. Please re-read #7 and do not mis-quote me.

salvis’s picture

Sorry — #7:

For all I know, it's a fundamental hard-coded limit of PDO, and not dependent on database/driver/config at all.

 

If so, then our function should be rewritten to enforce the limits of the language we are using.

I disagree. The first priority should be to work around any such limits, as transparently as possible.

In a layered architecture, upper layers shouldn't have to worry about constraints that can be handled in lower layers.

pillarsdotnet’s picture

Will salvis please file his own bug report against the Drupal core database system instead of trying to sidetrack this documentation issue?

jhodgdon’s picture

Status: Needs review » Needs work

No need to be snarky, pillarsdotnet... A polite request would be sufficient, but yes this is a doc issue.

So, back to the patch. You mentioned "out of memory errors", but do you know of this being a possibility? The only error I see in that other issue is a PDO error due to too many placeholders. The part you added to the doc doesn't even mention placeholders or explain how having "all the items in one query" would cause problems. Really, the problem is not that all the results come in one query, it's that the IN() clause has too many items in it, or that there are too may placeholders in the query.

Another thing... It looks like the problem is really in the entity loading controller called by entity_load(). You decided to document this in 3 functions, but there are many others that could be affected, right? So why did you decide on this particular list of 3 functions? It seems a bit arbitrary... and besides the entity loading controller is pluggable.

So I think the best thing would be to document it on entity_load as affecting the default entity controller, and on the functions in the default controller that are affected, and maybe put a statement like:

See entity_load()'s $ids parameter for information about limitations on the $nids argument.

on other functions that might be affected by this. And then in entity_load()'s $ids parameter, maybe something like this to better (I hope) document what is going on:

The default entity controller uses a query that puts all of the individual IDs into the query as placeholders in an IN() SQL statement. Having too many IDs in the array will lead to an overflow error.

pillarsdotnet’s picture

Status: Needs work » Closed (duplicate)

You mentioned "out of memory errors", but do you know of this being a possibility?

Since all of the node objects are being loaded into memory before being deleted, I imagine that in certain edge cases (very complex nodes in combination with a very small PHP memory_limit) there could be an out-of-memory issue. In my experience, this manifests as weird syntax errors in code that is actually syntactically correct.

The only error I see in that other issue is a PDO error due to too many placeholders.

I'm sure you are more knowledgable than I, but what experience I have in database optimization leads me to believe that extremely long and/or complex queries are detrimental to performance, quite aside from any limits built in to the PDO code.

The part you added to the doc doesn't even mention placeholders or explain how having "all the items in one query" would cause problems.

I try to write documentation from a user standpoint, not from a systems engineering standpoint. All the user needs to know is that putting too many items in that array can lead to errors.

Really, the problem is not that all the results come in one query, it's that the IN() clause has too many items in it, or that there are too may placeholders in the query.

The problem is that the current code and documentation assumes that it is possible and practical to produce unlimited-length SQL queries which load unlimited amounts of data into RAM.

You decided to document this in 3 functions, but there are many others that could be affected, right? So why did you decide on this particular list of 3 functions? It seems a bit arbitrary.

We scratch our own itch. But you're right; I should have submitted three patches, not one.

Marking this a duplicate in favor of:

jhodgdon’s picture

Title: Note limited argument length in node_delete_multiple(), node_load_multiple(), and buildQuery() functions. » Note limited argument length in entity_load() and other functions that call it.
Status: Closed (duplicate) » Active

Why open those three issues when the real problem is entity_load and the default controller? Wrong solution, IMO.

pillarsdotnet’s picture

Why open those three issues

Because then you can debate those three issues separately rather than arguing about whether I've managed to find every single function whose documentation exhibits this bug.

when the real problem is entity_load and the default controller?

Actually, the lowest-level function in the call chain is DatabaseCondition::compile().

I got a fatal error while using a very popular Drupal module. I submitted a patch to fix the fatal error, and was told that the module is working as designed. I submitted a documentation patch to help future programmers avoid the fatal error, and am being told that I have wrongly documented the wrong functions. Therefore, I have posted comments to the relevant API pages as a stopgap measure.

At this point, I don't care anymore.

jhodgdon’s picture

OK. Well let's just document it in *one* place, so that if the code gets fixed, we won't have to go back and fix the doc everywhere else, and put in some references.

Sorry you don't care any more. Hopefully someone else will make a patch that patches the doc in a way that is maintainable and correct.

droplet’s picture

sub from #1212148: Document limited size of the $nids array argument to node_load_multiple() function.

I have a test on it, doesn't like memory issue (Mysql 5 + PHP5.2/5.3)
http://drupal.org/node/1212148#comment-4708288

But i notice @pillarsdotnet is using (PHP 5.5.0 with memory_limit set to 256M, PDO/sqlite3 database)

PHP 5.5.0 ??

can you test it with mysql ? maybe an issue only happen on sqlite3

pillarsdotnet’s picture

From http://www.sqlite.org/limits.html:

Maximum Number Of Host Parameters In A Single SQL Statement

A host parameter is a place-holder in an SQL statement that is filled in using one of the sqlite3_bind_XXXX() interfaces. Many SQL programmers are familiar with using a question mark ("?") as a host parameter. SQLite also supports named host parameters prefaced by ":", "$", or "@" and numbered host parameters of the form "?123".

Each host parameter in an SQLite statement is assigned a number. The numbers normally begin with 1 and increase by one with each new parameter. However, when the "?123" form is used, the host parameter number is the number that follows the question mark.

SQLite allocates space to hold all host parameters between 1 and the largest host parameter number used. Hence, an SQL statement that contains a host parameter like 1000000000 would require gigabytes of storage. This could easily overwhelm the resources of the host machine. To prevent excessive memory allocations, the maximum value of a host parameter number is SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999.

The maximum host parameter number can be lowered at run-time using the sqlite3_limit(db, SQLITE_LIMIT_VARIABLE_NUMBER, size) interface.

droplet’s picture

we are better to patch DBTNG to limit it in SQLite

pillarsdotnet’s picture

FileSize
18.3 KB

I recompiled sqlite with SQLITE_MAX_VARIABLE_NUMBER set to 65536, then recompiled PHP, and performed the same test with the same results.

--- sqlite3-3.7.4/src/sqliteLimit.h     2010-11-29 11:24:18.000000000 -0500
+++ sqlite3-3.7.4-patched/src/sqliteLimit.h     2011-07-08 12:54:25.391881511 -0400
@@ -130,7 +130,7 @@
 ** The maximum value of a ?nnn wildcard that the parser will accept.
 */
 #ifndef SQLITE_MAX_VARIABLE_NUMBER
-# define SQLITE_MAX_VARIABLE_NUMBER 999
+# define SQLITE_MAX_VARIABLE_NUMBER 65536
 #endif
 
 /* Maximum page size.  The upper bound on this value is 65536.  This a limit
kmajzlik’s picture

Limit of arguments for sqlsrv = 2100. Strange thing.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

larowlan’s picture

Title: Note limited argument length in entity_load() and other functions that call it. » Document that operations that delete in bulk can hit limits for the number of arguments
Category: Bug report » Task
Issue summary: View changes
Issue tags: +Bug Smash Initiative

As this is documentation, its just a task.

Updated the title and issue summary

geek-merlin’s picture

I disagree with the direction of this. Yes, we have limits on the DB level, which depends on DB type.
Instead of putting the burden of messing with this on higher level, we should fix the DB driver.

#2031261: Make SQLite faster by combining multiple inserts and updates in a single query has working code for this, and even a report of chunking improving performance.
So let's treat this as a BUG or TASK for the DB driver like "Fix DB limits via chunking"

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.