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

Bug: Incorrect processing of the function in OrderBy #9212

Open
avegacms opened this issue Oct 2, 2024 · 9 comments
Open

Bug: Incorrect processing of the function in OrderBy #9212

avegacms opened this issue Oct 2, 2024 · 9 comments
Labels
database Issues or pull requests that affect the database layer

Comments

@avegacms
Copy link
Contributor

avegacms commented Oct 2, 2024

PHP Version

8.2

CodeIgniter4 Version

4.5.5

CodeIgniter4 Installation Method

Composer (using codeigniter4/appstarter)

Which operating systems have you tested for this bug?

Linux

Which server did you use?

apache

Database

PostgreSQL 15.8

What happened?

when writing a query (in PostgreSQL), it became necessary to sort with the TO_CHAR function, but we get an error at the output: ASC is applied twice

Steps to Reproduce

$this->builder()->select(
                    [
                        'COUNT(lottery_coupons.id) AS regCoupons',
                        "TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD HH24:00:00') AS hourInterval"
                    ]
                )->where(['lottery_coupons.is_reg' => 1])
                    ->groupStart()
                    ->where("lottery_coupons.updated_at::time BETWEEN '09:00:00'::time AND '20:00:00'::time",escape: false)
                    ->groupEnd()
                    ->groupBy("hourInterval")
                    ->orderBy("hourInterval", 'ASC');

                $result = $this->asArray()->findAll();

Expected Output

SELECT COUNT(lottery_coupons.id) AS regCoupons, TO_CHAR(lottery_coupons.updated_at, '%Y-%m-%d %H:00:00') AS hourInterval FROM "lottery_coupons" WHERE "lottery_coupons"."is_reg" = 1 AND ( "lottery_coupons"."updated_at" BETWEEN TO_TIMESTAMP(TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD 09:00:00'), 'YYYY-MM-DD HH24:MI:SS') AND TO_TIMESTAMP(TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD 20:00:00'), 'YYYY-MM-DD HH24:MI:SS') ) GROUP BY TO_CHAR(lottery_coupons.updated_at, "%Y-%m-%d %H:00:00") ORDER BY TO_CHAR(lottery_coupons.updated_at ASC, 'YYYY-MM-DD HH24:00:00') ASC

Anything else?

No response

@avegacms avegacms added the bug Verified issues on the current code behavior or pull requests that will fix them label Oct 2, 2024
@kenjis
Copy link
Member

kenjis commented Oct 3, 2024

but we get an error at the output: ASC is applied twice

What do you mean? What is the exact error message?

@kenjis kenjis added the database Issues or pull requests that affect the database layer label Oct 3, 2024
@avegacms
Copy link
Contributor Author

avegacms commented Oct 3, 2024

but we get an error at the output: ASC is applied twice

What do you mean? What is the exact error message?

The following error is written in the logs and an extra ASC is added

query

Problem in this code vendor/codeigniter4/framework/system/Database/BaseBuilder.php line 1486
problem

@kenjis
Copy link
Member

kenjis commented Oct 3, 2024

The first parameter contains the name of the column you would like to order by.
https://codeigniter4.github.io/CodeIgniter4/database/query_builder.html#orderby

Do you think the following is the name of the column?
"TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD HH24:00:00')"

@kenjis kenjis removed the bug Verified issues on the current code behavior or pull requests that will fix them label Oct 3, 2024
@avegacms
Copy link
Contributor Author

avegacms commented Oct 3, 2024

The first parameter contains the name of the column you would like to order by.
https://codeigniter4.github.io/CodeIgniter4/database/query_builder.html#orderby

Do you think the following is the name of the column? "TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD HH24:00:00')"

es, I had to use the TO_CHAR function(lottery_coupons.updated_at, 'YYYY-MM-DD HH24:00:00') instead of an alias, because the error "pg_query(): Query failed: ERROR: column" hourInterval" does not exist
LINE 8: ORDER BY "hourInterval" ASC"

log - log
query1 - query

@kenjis
Copy link
Member

kenjis commented Oct 3, 2024

Could you paste text instead of screenshots? Screenshots are difficult to read.

@avegacms
Copy link
Contributor Author

avegacms commented Oct 3, 2024

Could you paste text instead of screenshots? Screenshots are difficult to read.
Logs:

CRITICAL - 2024-10-03 11:05:19 --> [Caused by] ErrorException: pg_query(): Query failed: ERROR:  column "hourInterval" does not exist
LINE 8: ORDER BY "hourInterval" ASC
                 ^
in SYSTEMPATH/Database/Postgre/Connection.php on line 204.
 1 [internal function]: CodeIgniter\Debug\Exceptions->errorHandler(2, 'pg_query(): Query failed: ERROR:  column "hourInterval" does not exist
LINE 8: ORDER BY "hourInterval" ASC
                 ^', '/shared/httpd/lotteryapi/vendor/codeigniter4/framework/system/Database/Postgre/Connection.php', 204)
 2 SYSTEMPATH/Database/Postgre/Connection.php(204): pg_query(Object(PgSql\Connection), 'SELECT COUNT(lottery_coupons.id) AS regCoupons, TO_CHAR(lottery_coupons.updated_at, \'YYYY-MM-DD HH24:00:00\') AS hourInterval
FROM "lottery_coupons"
WHERE "lottery_coupons"."is_reg" = 1
AND   (
lottery_coupons.updated_at::time BETWEEN \'09:00:00\'::time AND \'20:00:00\'::time
 )
GROUP BY "hourInterval"
ORDER BY "hourInterval" ASC')
 3 SYSTEMPATH/Database/BaseConnection.php(734): CodeIgniter\Database\Postgre\Connection->execute('SELECT COUNT(lottery_coupons.id) AS regCoupons, TO_CHAR(lottery_coupons.updated_at, \'YYYY-MM-DD HH24:00:00\') AS hourInterval
FROM "lottery_coupons"
WHERE "lottery_coupons"."is_reg" = 1
AND   (
lottery_coupons.updated_at::time BETWEEN \'09:00:00\'::time AND \'20:00:00\'::time
 )
GROUP BY "hourInterval"
ORDER BY "hourInterval" ASC')
 4 SYSTEMPATH/Database/BaseConnection.php(648): CodeIgniter\Database\BaseConnection->simpleQuery('SELECT COUNT(lottery_coupons.id) AS regCoupons, TO_CHAR(lottery_coupons.updated_at, \'YYYY-MM-DD HH24:00:00\') AS hourInterval
FROM "lottery_coupons"
WHERE "lottery_coupons"."is_reg" = 1
AND   (
lottery_coupons.updated_at::time BETWEEN \'09:00:00\'::time AND \'20:00:00\'::time
 )
GROUP BY "hourInterval"
ORDER BY "hourInterval" ASC')
 5 SYSTEMPATH/Database/BaseBuilder.php(1644): CodeIgniter\Database\BaseConnection->query('SELECT COUNT(lottery_coupons.id) AS regCoupons, TO_CHAR(lottery_coupons.updated_at, \'YYYY-MM-DD HH24:00:00\') AS hourInterval
FROM "lottery_coupons"
WHERE "lottery_coupons"."is_reg" = :lottery_coupons.is_reg:
AND   (
lottery_coupons.updated_at::time BETWEEN \'09:00:00\'::time AND \'20:00:00\'::time
 )
GROUP BY "hourInterval"
ORDER BY "hourInterval" ASC', [...], false)

query

$this->builder()->select(
                    [
                        'COUNT(lottery_coupons.id) AS regCoupons',
                        "TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD HH24:00:00') AS hourInterval"
                    ]
                )->where(['lottery_coupons.is_reg' => 1])
                    ->groupStart()
                    ->where("lottery_coupons.updated_at::time BETWEEN '09:00:00'::time AND '20:00:00'::time",escape: false)
                    ->groupEnd()
                    ->groupBy("hourInterval")
                    ->orderBy("hourInterval", 'ASC');

                $result = $this->asArray()->findAll();

@kenjis
Copy link
Member

kenjis commented Oct 3, 2024

In my understanding, when using Query Builder, if you do not specify simple column names, try to set $escape to false (and surely escape by yourself).

If an alias cannot be used in group by, it is an issue (or specification) in PostgreSQL. Not in the framework.

@avegacms
Copy link
Contributor Author

avegacms commented Oct 3, 2024

In my understanding, when using Query Builder, if you do not specify simple column names, try to set $escape to false (and surely escape by yourself).

If an alias cannot be used in group by, it is an issue (or specification) in PostgreSQL. Not in the framework.

Thank you for the answer. In this form, the query works.

$this->builder()->select(
                    [
                        'COUNT(lottery_coupons.id) AS regCoupons',
                        "TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD HH24:00:00') AS hourInterval"
                    ]
                )->where(['lottery_coupons.is_reg' => 1])
                    ->groupStart()
                    ->where("lottery_coupons.updated_at::time BETWEEN '09:00:00'::time AND '20:00:00'::time",escape: false)
                    ->groupEnd()
                    ->groupBy('hourInterval', escape: false)
                    ->orderBy('hourInterval', 'ASC', false);

                $result = $this->asArray()->findAll();

But it is very strange that for some reason you need to disable escape for the groupBy and OrderBy methods - it seems to me that CI - PostgreSQL has a problem with escaping them

@kenjis
Copy link
Member

kenjis commented Oct 3, 2024

As you say, it is a bit strange.
To be honest, I don't know why the following query causes the error column "hourInterval" does not exist.

SELECT COUNT(lottery_coupons.id) AS regCoupons, TO_CHAR(lottery_coupons.updated_at, 'YYYY-MM-DD HH24:00:00') AS hourInterval
FROM "lottery_coupons"
WHERE "lottery_coupons"."is_reg" = 1
AND   (
lottery_coupons.updated_at::time BETWEEN '09:00:00'::time AND '20:00:00'::time
 )
GROUP BY "hourInterval"
ORDER BY "hourInterval" ASC

If you find the cause, feel free to send a PR to fix the issue.
https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
database Issues or pull requests that affect the database layer
Projects
None yet
Development

No branches or pull requests

2 participants