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

Nesting/unnesting many/catListTable crashes? #168

Open
tomjaguarpaw opened this issue Feb 18, 2022 · 8 comments
Open

Nesting/unnesting many/catListTable crashes? #168

tomjaguarpaw opened this issue Feb 18, 2022 · 8 comments

Comments

@tomjaguarpaw
Copy link
Contributor

Consider the following Rel8 program. It produces SQL which crashes.

Query Error: error: could not identify column "f1" in record data type

Is this known/expected?

The ultimate problem is that .f1, .f2, etc. for accessing fields of ROWs don't really work "through" SELECTs.

*Rel8 Data.Int Prelude> putStr $ showQuery $ do { q1 <- many (many (values [1 , 2 :: Expr Int16])); q2 <- catListTable q1; catListTable q2 }
SELECT
CAST("unnest0_9" AS int2) as "anon"
FROM (SELECT
      UNNEST("unnest0_7") as "unnest0_9",
      *
      FROM (SELECT
            (UNNEST(CASE WHEN ("rebind0_5") IS NULL THEN CAST(ARRAY[] AS record[]) ELSE "result0_4" END)).f1 as "unnest0_7",
            *
            FROM (SELECT *
                  FROM
                  (SELECT
                   0) as "T1"
                  LEFT OUTER JOIN
                  (SELECT
                   TRUE as "rebind0_5",
                   *
                   FROM (SELECT
                         *
                         FROM (SELECT
                               ARRAY_AGG("inner0_4") as "result0_4"
                               FROM (SELECT
                                     ROW(CASE WHEN ("rebind0_3") IS NULL THEN CAST(ARRAY[] AS int2[]) ELSE "result0_2" END) as "inner0_4",
                                     *
                                     FROM (SELECT *
                                           FROM
                                           (SELECT
                                            0) as "T1"
                                           LEFT OUTER JOIN
                                           (SELECT
                                            TRUE as "rebind0_3",
                                            *
                                            FROM (SELECT
                                                  *
                                                  FROM (SELECT
                                                        ARRAY_AGG("inner0_2") as "result0_2"
                                                        FROM (SELECT
                                                              "values0_1" as "inner0_2",
                                                              *
                                                              FROM (SELECT
                                                                    *
                                                                    FROM (SELECT "column1" as "values0_1"
                                                                          FROM
                                                                          (VALUES
                                                                           (CAST(1 AS int2)),
                                                                           (CAST(2 AS int2))) as "V") as "T1") as "T1") as "T1"
                                                        GROUP BY COALESCE(0)) as "T1") as "T1") as "T2"
                                           ON
                                           TRUE) as "T1") as "T1"
                               GROUP BY COALESCE(0)) as "T1") as "T1") as "T2"
                  ON
                  TRUE) as "T1") as "T1") as "T1"
@ocharles
Copy link
Contributor

What version of PostgreSQL are you on? We somewhat know about this, and afaik it works on newer PostgreSQL versions. On older ones, the fix is to use castTable with many. Can you share the Haskell that produced this crashing query?

@tomjaguarpaw
Copy link
Contributor Author

It fails in every version of Postgres on DB Fiddle. In fact it seems that .f1 syntax for extracting fields of anonymous rows was first supported in v13, yet v13 doesn't support this particular usage (which is a flaw of Postgres I think).

The Haskell is in my post above:

do { q1 <- many (many (values [1 , 2 :: Expr Int16])); q2 <- catListTable q1; catListTable q2 }

@ocharles
Copy link
Contributor

Thanks, I missed that this was in GHCI. Can you try changing some many x to many <$> x? I'll have a play soon myself

@tomjaguarpaw
Copy link
Contributor Author

Here is a full program that demonstrates the problem (requiring the hasql and tmp-postgres packages). castTable doesn't seem to help, but I'm not sure I'm using it right.

import Rel8
import Data.Int
import Hasql.Statement
import Hasql.Session
import Hasql.Connection
import Database.Postgres.Temp
import Data.Text (Text)

main = Database.Postgres.Temp.with $ \db -> do
  Right conn <- acquire (toConnectionString db)

  flip run conn $ statement () $ select $ do
    q1 <- castTable <$> many (castTable <$> many (values [1 , 2 :: Expr Int16]))
    q2 <- catListTable q1
    catListTable q2

@tomjaguarpaw
Copy link
Contributor Author

Can you try changing some many x to many <$> x?

That doesn't seem to type check.

@ocharles
Copy link
Contributor

Sorry, I meant many x to many $ castTable <$> x

@tomjaguarpaw
Copy link
Contributor Author

I made that change, but it still crashes with the same error:

module Main where

import Rel8
import Data.Int
import Hasql.Statement
import Hasql.Session
import Hasql.Connection
import Database.Postgres.Temp

main = Database.Postgres.Temp.with $ \db -> do
  Right conn <- acquire (toConnectionString db)

  flip run conn $ statement () $ select $ do
    q1 <- many (castTable <$> (many (castTable <$> (values [1 , 2 :: Expr Int16]))))
    q2 <- catListTable q1
    catListTable q2

@ilyakooo0
Copy link

Is this possibly related to #219?

@shane-circuithub shane-circuithub changed the title Nesting/unnesting many/catMaybeTables crashes? Nesting/unnesting many/catListTable crashes? Jun 18, 2023
shane-circuithub added a commit that referenced this issue Jun 18, 2023
This is one possible "fix" to #168. With this `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decoder this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Jun 18, 2023
This is one possible "fix" to #168. With this `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decoder this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Jun 18, 2023
This is another possible "fix" to #168 (as opposed to #242). It doesn't really fix the problem, but it allows us to use two levels of `catListTable` instead of only one. Instead of trying to use Postgres's broken `.f1` syntax, we cast the anonymous record to text, remove the parentheses and quotes and unescape any escaped quotes or backslashes, and then cast the resulting text back to the appropriate type. The reason this only works one level deep is that if the type we cast the text back to is itself an anonymous record, then PostgreSQL doesn't know how to parse the text.

It's kind of ugly and hacky but it does work and otherwise maintains the status quo. Comparison operators on nested lists continue to work as before and we don't need to burden `DBType` with parsing nonsense.
shane-circuithub added a commit that referenced this issue Jun 18, 2023
This is another possible "fix" to #168 (as opposed to #242). It doesn't really fix the problem, but it allows us to use two levels of `catListTable` instead of only one. Instead of trying to use Postgres's broken `.f1` syntax, we cast the anonymous record to text, remove the parentheses and quotes and unescape any escaped quotes or backslashes, and then cast the resulting text back to the appropriate type. The reason this only works one level deep is that if the type we cast the text back to is itself an anonymous record, then PostgreSQL doesn't know how to parse the text.

It's kind of ugly and hacky but it does work and otherwise maintains the status quo. Comparison operators on nested lists continue to work as before and we don't need to burden `DBType` with parsing nonsense.
shane-circuithub added a commit that referenced this issue Jun 18, 2023
This is another possible "fix" to #168 (as opposed to #242). It doesn't really fix the problem, but it allows us to use two levels of `catListTable` instead of only one. Instead of trying to use Postgres's broken `.f1` syntax, we cast the anonymous record to text, remove the parentheses and quotes and unescape any escaped quotes or backslashes, and then cast the resulting text back to the appropriate type. The reason this only works one level deep is that if the type we cast the text back to is itself an anonymous record, then PostgreSQL doesn't know how to parse the text.

It's kind of ugly and hacky but it does work and otherwise maintains the status quo. Comparison operators on nested lists continue to work as before and we don't need to burden `DBType` with parsing nonsense.
shane-circuithub added a commit that referenced this issue Jun 18, 2023
This is another possible "fix" to #168 (as opposed to #242). It doesn't really fix the problem, but it allows us to use two levels of `catListTable` instead of only one. Instead of trying to use Postgres's broken `.f1` syntax, we cast the anonymous record to text, remove the parentheses and quotes and unescape any escaped quotes or backslashes, and then cast the resulting text back to the appropriate type. The reason this only works one level deep is that if the type we cast the text back to is itself an anonymous record, then PostgreSQL doesn't know how to parse the text.

It's kind of ugly and hacky but it does work and otherwise maintains the status quo. Comparison operators on nested lists continue to work as before and we don't need to burden `DBType` with parsing nonsense.
shane-circuithub added a commit that referenced this issue Jun 18, 2023
This is one possible "fix" to #168. With this `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decoder this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Aug 15, 2023
This is one possible "fix" to #168. With this `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decoder this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Aug 16, 2023
This is one possible "fix" to #168. With this we can `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decode this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Aug 25, 2023
This is one possible "fix" to #168. With this we can `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decode this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Sep 21, 2023
This is one possible "fix" to #168. With this we can `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decode this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Sep 27, 2023
This is one possible "fix" to #168. With this we can `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decode this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
shane-circuithub added a commit that referenced this issue Sep 27, 2023
…242)

This is one possible "fix" to #168. With this we can `catListTable` arbitrarily deep trees of `ListTable`s.

It comes at a relatively high cost, however.

Currently we represent nested arrays with anonymous records. This works reasonably well, except that we can't extract the field from the anonymous record when we need it (PostgreSQL [theoretically](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.16.5.6) suports `.f1` syntax since PG13 but it only works in very limited situations). But it does mean we can decode the results using Hasql's binary decoders, and ordering works how we expect ('array[row(array[9])] < array[row(array[10])]'.

What this PR does is instead represent nested arrays as text. To be able to decode this, we need each 'DBType' to supply a text parser in addition to a binary decoder. It also means that ordering is no longer intuitive, because `array[array[9]::text] > array[array[10]::text]`. However, it does mean we can nest `catListTable`s to our heart's content and it will always just work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants