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

[5.x]: Invalid PostgreSQL query generated #14860

Closed
borispran opened this issue Apr 25, 2024 · 4 comments
Closed

[5.x]: Invalid PostgreSQL query generated #14860

borispran opened this issue Apr 25, 2024 · 4 comments
Assignees
Labels

Comments

@borispran
Copy link

What happened?

Description

Invalid SQL query is generated for PostgresSQL.

Works on MySQL!

Steps to reproduce

  1. Create field of checkboxes type (I named it purpose). Add two options (first, second).
  2. Create entry type and add previously created field to it.
  3. Create section and one entry.
  4. Go to GraphQL console

{ entries { id } }

returns one entry, but when filter by field value

{ entries(purpose: "first") { id } }

an exception is thrown:

ERROR:  operator does not exist: text @> jsonb
LINE 17: ...nt"#>>'{"3dbe2731-4531-4906-8345-9e2b629a4251"}') @> '"first...
                                                              ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

Here is the generated SQL:

SELECT
    "elements"."id", "elements"."canonicalId", "elements"."fieldLayoutId", "elements"."uid",
    "elements"."enabled", "elements"."archived", "elements"."dateLastMerged", "elements"."dateCreated",
    "elements"."dateUpdated", "elements_sites"."id" AS "siteSettingsId", "elements_sites"."siteId",
    "elements_sites"."title", "elements_sites"."slug", "elements_sites"."uri", "elements_sites"."content",
    "elements_sites"."enabled" AS "enabledForSite", "entries"."sectionId", "entries"."fieldId",
    "entries"."primaryOwnerId", "entries"."typeId", "entries"."postDate", "entries"."expiryDate",
    "structureelements"."root", "structureelements"."lft", "structureelements"."rgt", "structureelements"."level",
    "structureelements"."structureId"
FROM (
    SELECT "elements"."id" AS "elementsId", "elements_sites"."id" AS "siteSettingsId", "structureelements"."structureId" FROM "elements" "elements"
        INNER JOIN "entries" "entries" ON "entries"."id" = "elements"."id"
        INNER JOIN "elements_sites" "elements_sites" ON "elements_sites"."elementId" = "elements"."id"
        LEFT JOIN "structureelements" "structureelements" ON ("structureelements"."elementId" = "elements"."id") AND (
            EXISTS (SELECT * FROM "structures" WHERE ("id" = "structureelements"."structureId") AND ("dateDeleted" IS NULL)))
    WHERE ("entries"."sectionId"=1) AND 
        ((("elements_sites"."content"#>>'{"3dbe2731-4531-4906-8345-9e2b629a4251"}') @> '"first"'::jsonb)) AND 
        ((("elements"."enabled"=TRUE) AND ("elements_sites"."enabled"=TRUE)) AND 
        ("entries"."postDate" <= '2024-04-25 13:04:59') AND 
        (("entries"."expiryDate" IS NULL) OR ("entries"."expiryDate" > '2024-04-25 13:04:59'))) AND 
        ("elements"."archived"=FALSE) AND 
        ("elements"."dateDeleted" IS NULL) AND 
        ("elements"."draftId" IS NULL) AND 
        ("elements"."revisionId" IS NULL) 
    ORDER BY "structureelements"."lft", "entries"."postDate" DESC, "elements"."id" DESC
) "subquery"
    INNER JOIN "elements" "elements" ON "elements"."id" = "subquery"."elementsId"
    INNER JOIN "elements_sites" "elements_sites" ON "elements_sites"."id" = "subquery"."siteSettingsId"
    INNER JOIN "entries" "entries" ON "entries"."id" = "subquery"."elementsId"
    LEFT JOIN "structureelements" "structureelements" ON ("structureelements"."elementId" = "subquery"."elementsId") AND ("structureelements"."structureId" = "subquery"."structureId")
ORDER BY "structureelements"."lft", "entries"."postDate" DESC, "elements"."id" DESC

Problem is here:

((("elements_sites"."content"#>>'{"3dbe2731-4531-4906-8345-9e2b629a4251"}') @> '"first"'::jsonb))

this line is built in

public function jsonExtract(string $column, array $path): string
{
$column = $this->db->quoteColumnName($column);
$path = $this->db->quoteValue(
sprintf('{%s}', implode(',', array_map(fn(string $seg) => sprintf('"%s"', $seg), $path)))
);
return "($column#>>$path)";
}

Changing operator from #>> (extract as text) to #> (extract as jsonb) or adding explicit cast to jsonb fixes the problem.

So line 142 could look like this return "($column#>$path)"; or this return "($column#>>$path)::jsonb"; whatever fits better to the rest of the query building code.

Craft CMS version

5.0.5

PHP version

8.2

Operating system and version

No response

Database type and version

No response

Image driver and version

No response

Installed plugins and versions

@i-just
Copy link
Contributor

i-just commented Apr 26, 2024

Hi, thanks for reporting! I raised a PR for this.

@brandonkelly
Copy link
Member

Craft 5.0.6 is out with that fix. Thanks again!

@richardcalahan
Copy link

I'm getting a similar error in 5.2.5

operator does not exist: jsonb ~~

@brandonkelly
Copy link
Member

@richardcalahan Can you post a new issue with a full stack trace + version info?

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

No branches or pull requests

4 participants