Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial PostgreSQL support #1933

Merged
merged 24 commits into from
Oct 7, 2020
Merged

Conversation

Wieter
Copy link
Contributor

@Wieter Wieter commented Oct 2, 2020

I've been working to get bolt compatible with PostgreSQL.
From my end everything seems to be working fine, good enough to be used for the purpose at hand (running at FreeBSD 12.1 \w PostgreSQL v11.6).
A quick check from my side on usage of MySQL and SQLite did not show serious problems after fixing a CAST specifically for MySQL (2707e71).

There might be some minor bugs still around (hence the WIP), that need user testing. For example something strange with the template used (bypassed in c68e6d5) where a selectfield does not have an .selectedIds (integer). Somehow sqlite & mysql have no problems with that, but postgres is more strict. There may arise more of those issues.

@Wieter Wieter changed the title WIP: Development postgres [WIP] Development postgres Oct 2, 2020
@bobdenotter
Copy link
Member

@Wieter Awesome, thank you for your work! 👍

I'll keep a close eye on this, and as soon as the [WIP] is removed, we'll merge it in!

@Wieter
Copy link
Contributor Author

Wieter commented Oct 2, 2020

@bobdenotter Sure no problem!
I'm just trying to improve the PostgreSQL (or better: database agnostic) compatibility while not breaking other things :)
A new (postgres-only), more tricky, issue popped up at the admin search /bolt/?filter=css
SQLSTATE[42883]: Undefined function: 7 ERROR: operator does not exist: jsonb ~~ unknown
LINE 1: ...t_type = $6) AND (b0_.status <> $7 AND (b2_.value LIKE $8 AN...
seems like b2_.value needs also to be casted to TEXT for non-mysql.
I didn't find out yet where the WHERE clause of this query gets assembled, might take some time.
Meanwhile I'm looking into the doctrine docs if this can be done automatically through the model annotation, which would be a silver bullet to cover for any remaining issues of the field_translation.value json-->jsonb change.

@bobdenotter
Copy link
Member

Two quick pointers:

  • Some of the "Json or not" stuff is handled in wrapJsonFunction() in src/Doctrine/JsonHelper.php. Perhaps the hasJson() method in src/Doctrine/Version.php needs to be adjusted, too.

  • The heavy lifting of the queries generated from {% setcontent %} tags is done here: src/Storage/Handler/SelectQueryHandler.php

Copy link
Member

@bobdenotter bobdenotter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shaping up nicely! 👍

I've left some comments/remarks in your changes.

@@ -24,7 +24,7 @@ DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/bolt.sqlite
#DATABASE_URL=mysql://db_user:"db_password"@localhost:3306/db_name

# Postgres
#DATABASE_URL=postgresql://db_user:"db_password"@localhost:5432/db_name?serverVersion=11"
#DATABASE_URL=postgresql://db_user:"db_password"@localhost:5432/db_name?serverVersion=11&charset=utf8"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is utf8 not the default? Do we need to explicitly set it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to explicitly set here, to force users to think about the charset.
Additionally, it is hardcoded in config/packages/doctrine.yaml as charset: utf8mb4, which is fine for MySQL but unsupported in PostgreSQL (for as far as I could find). Setting it in the DATABASE_URL ensures an override to UTF8.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, fair enough! Does Postgres still handle emoji properly, if it doesn't have utf8mb4?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emoji should work as they are UTF-8, I'll have to test it to know for sure.
From what I understand, MySQL utf-8 is not really full utf-8, it uses 3-bytes per character instead the regular 4byte. I do not know why it was decided, but here lies the origin: https://github.com/mysql/mysql-server/commit/43a506c0ced0e6ea101d3ab8b4b423ce3fa327d0
That's probably why for MySQL utf8mb4 is required. For postgres. utf8 is full utf8, so 4 byte.
something to keep in mind in case of problems -> https://stackoverflow.com/questions/36198847/what-type-should-i-use-to-store-emoji-in-postgresql

@@ -0,0 +1,3 @@
# Reference extension configuration file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file doesn't have to be committed.

@@ -31,8 +31,11 @@ doctrine:
alias: App
dql:
string_functions:
JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract
CAST: DoctrineExtensions\Query\Mysql\Cast
JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract # Why have a duplicate of the Scienta version?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that it used to be different. I'll check if that's still the case, or if we can fall back to the original. I'll get back to you on that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, looked it up: The Scienta versions (like src/Query/AST/Functions/Mysql/JsonExtract.php) are specific for SQLite, Mysql or Postgres. Ours extends AbstractJsonFunctionNode instead, and can be used on either.

config/packages/doctrine.yaml Outdated Show resolved Hide resolved
src/.preload.php Outdated
@@ -0,0 +1,5 @@
<?php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is not needed. I don't know where it came from, but I occasionally see it popping up on my end as well. Regardless, we can remove it here.

@@ -23,9 +23,19 @@ class JsonHelper
public static function wrapJsonFunction(?string $where = null, ?string $slug = null, Connection $connection)
{
$version = new Version($connection);
//print_r($version->getPlatform()['driver_name']); # pgsql
//exit(print($where)); // translations_anyField.value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove commented-out code

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sidenote: instead of print_r, use dump(). It's so much nicer. ;-)

https://symfony.com/doc/current/components/var_dumper.html#dump-examples-and-output

src/Doctrine/JsonHelper.php Outdated Show resolved Hide resolved
@@ -43,11 +43,14 @@
{% block extended_fields %}

{# Special case for 'select' fields: if it's a multiple select, the field is an array. #}
{# I dont know what is going on here, but field.selectedIds for pgsql showcase/mr-jean-feeney (and others) #}
{# yield field values, NOT integer IDs.. Also, selectedIds does not exists (try dump(field) ) #}
{# TODO: FIX IT, bypassing for now by setting field.id #}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird. Might be an unrelated bug, that's coming to light here.. I'll check this one out as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, took a look at this. Not sure why it was failing on your end.. {{ field.id }} is not a good fix, because it's an entirely different ID than the one(s) we need.

It uses method getSelectedIds from src/Entity/Field/SelectField.php, so it really should exist, if the field is a SelectField.

One thing you might try is to explicitly set it to return an array instead of one item:

{% setcontent selected = field.contentType where {'id': field.selectedIds} returnmultiple %}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be fixed now. selectedIds function returned full (string) values, instead of (integer)IDs. So, why not select on field.value: .. instead of field.id: .. :)
Works nicely in postgres, I still have to run a test for the others.

// JSON supported since SQLite version 3.9.0
public const SQLITE_WITH_JSON = '3.9.0';
// PHP supports SQLite since version 5.3.0
public const PHP_WITH_SQLITE = '5.3.0';
Copy link
Member

@bobdenotter bobdenotter Oct 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct. If we merge this in, Bolt will absolutely assume it has JSON support on installations where it doesn't have it.

Maybe we should change the name of the constant, because it's more "PHP_WITH_SQLITE_THAT_HAS_JSON_SUPPORT_BUNDLED". I've definitely seen this break on PHP 7.2 setups. (Ubuntu 2018.04, if i recall correctly). I'm aware that some installations on lower versions have this bundled, but we can't rely on it. Two examples are listed right above, as "Not OK".

Ideally, we could properly test if we have it, but I have not found a proper way to do that.. If you have a good suggestion, I'm all for it!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've written a small test and implemented in a new version (e827a79). Meanwhile I'll leave the (restored) old code commented out until we've fully tested everything. Cleanup is the last step.

@Wieter
Copy link
Contributor Author

Wieter commented Oct 5, 2020

@bobdenotter somehow the test fails, while if I manually perform the failed action in the test myself (by going to ../bolt/edit/44 and embedding the video) the correct output is given ("Matched embed" --> Silversun Pickups - Nightlight (Official Video), and Silversun Pickups)

For now, I'll leave it like this and work on something differently.

sidenote: it would be nice if a test can be run for database-specific implementation, i.e. postgres vs mysql.

@bobdenotter
Copy link
Member

@Wieter Travis failing is a known issue. It's a bit annoying, but i've restarted the build.

We have an issue in the works, where we'll improve it: #1918

@bobdenotter
Copy link
Member

Travis is extra special stubborn on this one! I'll fix the conflict and Travis checks on this PR, when i have a bit of time.. (i expect tomorrow!)

… ERROR: invalid input syntax for integer: "a voluptas possimus aut libero doloremque."") in "helpers/_field_blocks.twig".
@Wieter
Copy link
Contributor Author

Wieter commented Oct 6, 2020

It seems that for PostgreSQL on my side everything is working nicely, but other users should help test the full functionality as well, as bugs might be hidden.
Once the Travis tests pass I think we can remove [WIP] and implement the merge. Perhaps mark as "experimental PostgreSQL support"?

@bobdenotter
Copy link
Member

It looks like some of the tests are failing, because of the JSON check now. See: https://travis-ci.com/github/bolt/core/jobs/396066538

Schermafbeelding 2020-10-07 om 12 35 54

Schermafbeelding 2020-10-07 om 12 36 00

I'll see if I can reproduce that on my end!

@bobdenotter
Copy link
Member

@Wieter Tests are passing now!

Once the Travis tests pass I think we can remove [WIP] and implement the merge. Perhaps mark as "experimental PostgreSQL support"?

That sounds like the prudent thing to do! Let's roll with that.

Once again, thank you for your contribution on this feature!

@bobdenotter bobdenotter changed the title [WIP] Development postgres Initial PostgreSQL support Oct 7, 2020
@bobdenotter bobdenotter merged commit b6ba7a1 into bolt:master Oct 7, 2020
@Wieter
Copy link
Contributor Author

Wieter commented Oct 7, 2020

@bobdenotter You're welcome!
I see that while we are struggling with a new Ziggo modem (working now all day from a mobile hotspot..), you managed to fix the last bugs! Great!

@@ -21,7 +21,7 @@ class FieldTranslation implements TranslationInterface
*/
private $id;

/** @ORM\Column(type="json") */
/** @ORM\Column(type="json", options={"jsonb": true}) */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Wieter do you remember if this is part of the fix, or a improvement made on the fly?

Because this is causing trouble for me with mysql: #3281

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants