Problem/Motivation
We cannot add query conditions on a BLOB/bytea field reliably; in PostgreSQL, a condition value containing non-UTF data generates a
ERROR: invalid byte sequence for encoding "UTF8": ...
Proposed resolution
Add (the the ability to add) bindValue() calls to query arguments.
Original report
#2222635-14: Waiting for table metadata lock on cache_field table had output issues like #710940-10: Support for BINARY and VARBINARY in Database Schema
| Comment | File | Size | Author |
|---|---|---|---|
| #35 | 2238253-35.patch | 12.08 KB | daffie |
| #35 | interdiff-2238253-33-35.txt | 798 bytes | daffie |
| #27 | 2238253-27-test-only-without-extra-parameter.patch | 1.35 KB | daffie |
| #27 | 2238253-27-test-only.patch | 1.39 KB | daffie |
Comments
Comment #1
danblack commentedComment #2
danblack commentedTest case to show we've already got a problem:
---- Drupal\system\Tests\Database\InsertLobTest ----
Status Group Filename Line Function
--------------------------------------------------------------------------------
Pass Other DatabaseTestBase. 23 Drupal\system\Tests\Database\Databa
Enabled modules: database_test.
Pass Other DatabaseTestBase. 33 Drupal\system\Tests\Database\Databa
Installed database_test tables: {test}, {test_people}, {test_people_copy},
{test_one_blob}, {test_two_blobs}, {test_task}, {test_null},
{test_serialized}.
Pass Other InsertLobTest.php 28 Drupal\system\Tests\Database\Insert
Test data contains a NULL.
Pass Other InsertLobTest.php 33 Drupal\system\Tests\Database\Insert
Can insert a blob: id 1,
a:2:{s:2:"id";s:1:"1";s:5:"blob1";s:15:"This
isa test.";}.
Pass Other DatabaseTestBase. 23 Drupal\system\Tests\Database\Databa
Enabled modules: database_test.
Pass Other DatabaseTestBase. 33 Drupal\system\Tests\Database\Databa
Installed database_test tables: {test}, {test_people}, {test_people_copy},
{test_one_blob}, {test_two_blobs}, {test_task}, {test_null},
{test_serialized}.
Pass Other InsertLobTest.php 41 Drupal\system\Tests\Database\Insert
Test data contains a non-ascii bits.
Pass Other InsertLobTest.php 46 Drupal\system\Tests\Database\Insert
Can insert a blob: id 1, .
Fail Other InsertLobTest.php 48 Drupal\system\Tests\Database\Insert
Value '1' is equal to value NULL.
Fail Other InsertLobTest.php 49 Drupal\system\Tests\Database\Insert
Can select by a binary data: b:0;.
Pass Other DatabaseTestBase. 23 Drupal\system\Tests\Database\Databa
Enabled modules: database_test.
Pass Other DatabaseTestBase. 33 Drupal\system\Tests\Database\Databa
Installed database_test tables: {test}, {test_people}, {test_people_copy},
{test_one_blob}, {test_two_blobs}, {test_task}, {test_null},
{test_serialized}.
Pass Other InsertLobTest.php 63 Drupal\system\Tests\Database\Insert
Can insert multiple blobs per row.
Comment #3
danblack commentedsmall improvement - works in mysql and postgres but fails sqlite.
Needs a few more API changes to support $bindValue in other core/includes/database.php functions.
Comment #4
danblack commentedSeems why sqlite doesn't work is known http://stackoverflow.com/questions/18750043/bind-resource-to-a-pdo-lob-p...
Comment #5
danblack commentednext iteration that works around sqlite::PDO errors.
Comment #6
danblack commentedComment #9
danblack commentedadded API change in fake driver.
Comment #10
stefan.r commentedComment #13
bzrudi71 commentedNot sure what we did in the meantime, but currently at least for PostgreSQL all LOB tests do pass (insert and update tests on docker testbot). From the logs:
Comment #14
bzrudi71 commentedSeems this is still required for exactly one! failing test ;-) will see if so...
Comment #15
bzrudi71 commentedSorry, I have no time to check this over the next days...
Comment #16
grom358 commentedPatch reroll from comment #9
Comment #18
grom358 commentedComment #19
daffie commentedIt all looks good to me.
I made some minor documentation changes.
For me it is RTBC.
Comment #20
bzrudi71 commentedSorry, I think this needs at least testing for SQLite too and to be true, I never ever tested if this is still needed for pg/driver at all. At least I have seen no effect of this patch. Can we just try to run only the new tests without the patch itself first please, just to make sure?
Comment #21
daffie commentedI have ran the test with a PostgreSQL database and without the rest of the patch. I removed the extra parameters of one call in the test. The test fails.
Will try later with SQLite.
Comment #22
daffie commentedI ran the test with a SQLite database and no fails and no exceptions. No problems with SQLite for this patch!
Comment #23
bzrudi71 commentedThanks daffie for testing! I'm fine with the patch as is, but would prefer a second review from @mradcliffe before setting this RTBC.
Comment #27
daffie commentedSimple reroll. Added two extra patch with only the the added test. Because we are doing a api extension for the Drupal\Core\Database\Connection::query by adding an extra parameter, I have also added a test only patch without the extra parameter being called.
Comment #32
daffie commentedThe testbot is returning the following error: HP Fatal error: Call to undefined method Drupal\Core\Database\Driver\sqlite\Statement::bindValue() in /var/www/html/core/lib/Drupal/Core/Database/Connection.php on line 623
Comment #33
daffie commentedChanged Drupal\Core\Database\Driver\sqlite\Connection::query to be the same as the old Drupal\Core\Database\Connection::query, but the extra parameter.
Comment #35
daffie commentedMinor change to Drupal\Core\Database\Driver\sqlite\Connection::query. Adding the $bindValue to the calling of $this->expandArguments.
Comment #37
daffie commentedThis issue is a feature request, so moving this to 8.3.
Comment #38
mradcliffeTypo in comment. Should be "arguments".
If this were wrapped in a condition, then I don't think you would need to override the query method in sqlite driver.
If there were a method like canUseBindParameters(), and that's an opt-in thing in 8.3.x, then only mysql and pgsql would implement, and sqlite and any other driver would not need to make any changes.
Should this be its own method? That would mean passing the statement object with its state around, and that might not be desirable from a functional perspective.
This should be fine since indexed keys wouldn't be in $args, right?
Can't find anything other than that.
Comment #39
bzrudi71 commentedI didn't have a detailed look at the patch yet, but looking at:
https://dispatcher.drupalci.org/job/default/226878/
I'm a bit concerned about performance as the runtime was 1h 19min compared to around 56min for the usual branch run. Should we start a new test just to make sure?
Comment #40
daffie commented@bzrudi71: I did not looked at the run times. I have started to rerun the tests. If they are still as slow as the previous ones then we should move this issue to will not fix. Great find!
Comment #41
bzrudi71 commentedOkay, last run 1h 8min:
https://dispatcher.drupalci.org/job/default/242441/
Runtime for another issue that removes code from pg driver 1h 7min
#2057693: PostgreSQL orderBy method adds fields it doesn't need to, leading to fatal errors when the result is used as an insert subquery
https://dispatcher.drupalci.org/job/default/242468/
So this seems not to cause a bad performance impact. Anyway, looking at:
https://dispatcher.drupalci.org/job/php7_postgres9.1/buildTimeTrend
it is really annoying to see runtimes for the same branch tests differ that much :( The MySQL bot is always within 37-40 min. Should we ping the drupalCI guys?
Comment #42
daffie commentedMaybe we should wait until #2057693: PostgreSQL orderBy method adds fields it doesn't need to, leading to fatal errors when the result is used as an insert subquery and #1079762: DatabaseSchema_pgsql::queryTableInformation() is slow have landed. @bzrudi71: But if you want to contact the drupalCI guys that would also be great.
Comment #43
bzrudi71 commented@daffie good idea let's wait for the other issues to go in first. Opened #2821754: PostgreSQL runtime PingPong in the DrupalCI queue.
Comment #46
rosk0Comment #53
daffie commentedReroll is needed.
Comment #55
roderikComment #59
jonathanshawPostponed on #2057693: PostgreSQL orderBy method adds fields it doesn't need to, leading to fatal errors when the result is used as an insert subquery per #42.
Also needs an opinion from maintainer like @daffie on #38.2