Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem
In #2028679: After fresh SQLite install admin/config/content/panelizer is not shown. the some menu entry is not shown.
Inspecting watchdog from module enable shows the cause (truncated):
PDOException: SQLSTATE[HY000]: General error: 1 too many SQL variables: SELECT menu_links.link_path AS link_path, menu_links.mlid AS mlid, menu_links.router_path AS router_path, menu_links.updated AS updated FROM {menu_links} menu_links WHERE ( (updated = :db_condition_placeholder_0) OR( (router_path NOT IN (:db_condition_placeholder_1, :db_condition_placeholder_2, :db_condition_placeholder_3, :db_condition_placeholder_4,
+++ some omissions +++
:db_condition_placeholder_1193, :db_condition_placeholder_1194, :db_condition_placeholder_1195)) AND (external = :db_condition_placeholder_1196) AND (customized = :db_condition_placeholder_1197) )); Array ( [:db_condition_placeholder_0] => 1 [:db_condition_placeholder_1] => menu-dummy [:db_condition_placeholder_2] => node [:db_condition_placeholder_3] => r4032login [:db_condition_placeholder_4] => rss.xml [:db_condition_placeholder_5] => admin
+++ some omissions +++
[:db_condition_placeholder_1194] => admin/structure/types/manage/%/panelizer/token/%/revert [:db_condition_placeholder_1195] => admin/config/content/panelizer/%/%/list/%/revert [:db_condition_placeholder_1196] => 0 [:db_condition_placeholder_1197] => 1 ) in _menu_navigation_links_rebuild() (Zeile 2877 von /var/www/virtual/clsys/html/clsys/1306/includes/menu.inc).
Analysis
Offending D7 code in _menu_navigation_links_rebuild is (it's about the $paths variable)
$paths = array_keys($menu);
// Updated and customized items whose router paths are gone need new ones.
$result = db_select('menu_links', NULL, array('fetch' => PDO::FETCH_ASSOC))
->fields('menu_links', array(
'link_path',
'mlid',
'router_path',
'updated',
))
->condition(db_or()
->condition('updated', 1)
->condition(db_and()
->condition('router_path', $paths, 'NOT IN')
->condition('external', 0)
->condition('customized', 1)
)
)
->execute();
in D8 this code has moved to MenuLinkStorageController::loadUpdatedCustomized but it's still doing the same thing so filing against D8.
Comments
Comment #1
geek-merlinHmm, limit of 999 is hardcoded.
This seems tough.
Crosslinking an old noisy issue which suggests this issue may also appear when doing crud operations on a big count of entities: #1210092: PDOException: SQLSTATE[HY000]: General error: 1 too many SQL variables: SELECT t.* FROM {field_data_body} t WHERE (entity_type =
I think we have 3 levels of concern here:
* A menu router which breaks in nonspecial circumstances on SQLite. Raising prio as i suppose we want to target sqlite.
* A PDO driver which might want to magically circumvent this limit. If that's possible at all i suppose that's a tough one and should be a separate issue.
* Adding a warning to PDO developer docs that arrays in conditions do work but can hit DB limits.
Comment #2
geek-merlinIn fact there are 2 queries that break the limit.
I'm wondering if filtering in PHPland helps here and did a quick profiling on a D7 site:
So in PHPland we are way faster with a temporary memory footprint worse by some MB. (Gut feeling worst case: 6MB for 2000 items) Sounds like a reasonable deal. Here's the code for reference. I'll roll this in a patch after getting some sleep...
Comment #3
geek-merlinPatch flying in. 7.x for testbot.
Comment #4
geek-merlinSame for 8.x.
Comment #6
geek-merlinUrps, forget #3.
Comment #7
geek-merlinComment #8
geek-merlinOK and here's the improved 8.x version.
Maybe in the 2nd query we can get filtering out of phpland with some join but that's up to the who deeply grokks the menu system.
Comment #10
geek-merlinUh, this can't work because an entityquery just returns IDs. We need "select id, router_path"...
Need to grokk new EFQ.
Comment #11
Damien Tournoud CreditAttribution: Damien Tournoud commentedWould enabling
PDO::ATTR_EMULATE_PREPARES
on SQLite (we already do on both MySQL and PostgreSQL) workaround the problem?Comment #12
geek-merlinYes we should do that anyway and i rolled that in #2031261: Make SQLite faster by combining multiple inserts and updates in a single query.
BUT that patch alone does not solve the issue, the exception from the issue summary is still thrown.
So it looks we're back at #8.
Comment #13
geek-merlinOut of curiosity i used the code from #2 to profile #2031261: Make SQLite faster by combining multiple inserts and updates in a single query:
Without that patch:
With that patch:
Which shows that that patch speeds up query #2 from 50ms to 32ms.
Comment #14
Damien Tournoud CreditAttribution: Damien Tournoud commentedWhy would a "too many SQL variables" still be thrown if we are emulated prepared statements?
Comment #15
geek-merlindunno. re-tested it on a different install and still get exception.
can you check the patch in #2031261-2: Make SQLite faster by combining multiple inserts and updates in a single query if i got the right place for the option.
Comment #16
geek-merlinfor the records: here's a simple php snippet to trigger the exception:
EDIT: a range of integers does not raise the exception here. see #18
Comment #17
geek-merlini'm such a moron. forget #12 and #15.
after killing the fcgi process #2031261: Make SQLite faster by combining multiple inserts and updates in a single query in fact solves this issue.
leaving this open for reference and prioritizing the other issue.
Comment #17.0
geek-merlinUpdated issue summary.
Comment #18
geek-merlinI was WRONG thinking that the snippet in #16 raises the exception,
so i was WRONG that this issue is fixed by #2031261: Make SQLite faster by combining multiple inserts and updates in a single query.
It depends if we have string or int placeholders.
@damien: here's the proof that PDO::ATTR_EMULATE_PREPARES does not help, maybe it's broken in PDO sqlite.
* aplied patch from #2031261: Make SQLite faster by combining multiple inserts and updates in a single query
* running this code in devel/php raises the "too many sql variables" exception
Remarkable that only an array of strings raises the exception.
(EDIT: ah, i see: sqlite has some hack in \DatabaseStatement_sqlite::getStatement() where is replaces numeric placeholders itself.)
Comment #19
geek-merlinSo the general solution is worked on over there: #2031261: Make SQLite faster by combining multiple inserts and updates in a single query
Comment #20
valthebaldIf #2031261: Make SQLite faster by combining multiple inserts and updates in a single query should fix the issue, can this issue be closed as duplicate?
Comment #21
geek-merlinRite!