mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 21:43:06 +01:00
110 lines
4.6 KiB
Python
110 lines
4.6 KiB
Python
|
#coding:utf-8
|
||
|
|
||
|
"""
|
||
|
ID: issue-7853
|
||
|
ISSUE: 7853
|
||
|
TITLE: Do not consider non-deterministic expressions as invariants in pre-filters
|
||
|
DESCRIPTION:
|
||
|
Change in FB 5.x was pushed 14.12.2023 20:06:
|
||
|
https://github.com/FirebirdSQL/firebird/commit/f0b7429a1873ed9470838da61bdca0bce748652d
|
||
|
Functions gen_id(), rand(), gen_uuid(), rdb$set_context and some other are not considered as deterministic anymore.
|
||
|
It means that explained plans for queries which used these functions will change: now they must NOT contain 'Filter (preliminary)'.
|
||
|
This behavior changed since snapshot 5.0.0.1304 (date: 16-dec-2023).
|
||
|
NOTES:
|
||
|
[17.12.2023] pzotov
|
||
|
1. Explained plans for queries where 'tmain' have aliases 'm0' ... 'm4' have:
|
||
|
* 'Filter (preliminary)' - for snapshots before this fix
|
||
|
* 'Filter' (WITHOUT preliminary) - after fix
|
||
|
2. Last commit in the push is "deterministic uncorrelated subqueries to be considered as invariants" - but there is NO DIFFERENCE
|
||
|
between explained plans for 5.x snapshots that belongs to time points just _before_ and _after_ this push.
|
||
|
This is because push of PR#7853 has several commits, and one of them did broke such functionality whereas next
|
||
|
commit - WITHIN THIS PUSH (!) - did restore previous state (letter by dimitr, 17.12.2023 21:17).
|
||
|
|
||
|
3. Actually, NON-correlated subqueries became considered as INVARIANT much earlier, since 5.0.0.890, 10-jan-2023
|
||
|
("Merge pull request #7441 from FirebirdSQL/v5-pretty-explained-plan", a6ce0ec1632ec037b41b9cbcad42fd3ce6a9ea5e).
|
||
|
It seems that this old commit (of 10-jan-2023) caused lot of old issues to be considered now as fixed, for example
|
||
|
https://github.com/FirebirdSQL/firebird/issues/3394
|
||
|
Query where 'tmain' table has alias 'm4' (and 'tdetl' table is involved - in contrary to all other queries) - is from this ticket.
|
||
|
This query explained plan must have "Sub-query (invariant)" since build 5.0.0.890
|
||
|
|
||
|
Checked on 5.0.0.1304
|
||
|
::: NB ::: Build 6.0.0.180 - FAILS because this PR still not pushed in master branch. Waiting for commit.
|
||
|
"""
|
||
|
|
||
|
import pytest
|
||
|
from firebird.qa import *
|
||
|
|
||
|
|
||
|
init_sql = """
|
||
|
set bail on;
|
||
|
recreate sequence g;
|
||
|
recreate table tmain(id int primary key using index tmain_pk, f01 int);
|
||
|
recreate table tdetl(id int primary key using index tdetl_pk, pid int references tmain(id) using index tdetl_fk, f01 int);
|
||
|
|
||
|
insert into tmain(id, f01) select row_number()over(), rand()* 1000 from rdb$types rows 100;
|
||
|
insert into tdetl(id, pid, f01) select row_number()over(), 1+rand() * 49, rand()* 1000 from rdb$types,rdb$types rows 1000;
|
||
|
commit;
|
||
|
set statistics index tmain_pk;
|
||
|
set statistics index tdetl_fk;
|
||
|
commit;
|
||
|
"""
|
||
|
|
||
|
db = db_factory(init = init_sql)
|
||
|
|
||
|
query_lst = (
|
||
|
"select count(*) from tmain m0 where gen_id(g,0) = 0"
|
||
|
,"select count(*) from tmain m1 where rand() > 0.5"
|
||
|
,"select count(*) from tmain m2 where gen_uuid() is not null"
|
||
|
,"select count(*) from tmain m3 where coalesce( rdb$set_context('USER_TRANSACTION', 'ROWS_COUNTER',cast(coalesce(rdb$get_context('USER_TRANSACTION', 'ROWS_COUNTER'),'0') as int) + 1 ), 0) >= 0"
|
||
|
,"select count(*) from tmain m4 where m4.f01 > ( select avg(f01) from tdetl d )"
|
||
|
)
|
||
|
|
||
|
act = python_act('db')
|
||
|
|
||
|
expected_stdout = """
|
||
|
Select Expression
|
||
|
####-> Aggregate
|
||
|
########-> Filter
|
||
|
############-> Table "TMAIN" as "M0" Full Scan
|
||
|
|
||
|
Select Expression
|
||
|
####-> Aggregate
|
||
|
########-> Filter
|
||
|
############-> Table "TMAIN" as "M1" Full Scan
|
||
|
|
||
|
Select Expression
|
||
|
####-> Aggregate
|
||
|
########-> Filter
|
||
|
############-> Table "TMAIN" as "M2" Full Scan
|
||
|
|
||
|
Select Expression
|
||
|
####-> Aggregate
|
||
|
########-> Filter
|
||
|
############-> Table "TMAIN" as "M3" Full Scan
|
||
|
|
||
|
Sub-query (invariant)
|
||
|
####-> Singularity Check
|
||
|
########-> Aggregate
|
||
|
############-> Table "TDETL" as "D" Full Scan
|
||
|
Select Expression
|
||
|
####-> Aggregate
|
||
|
########-> Filter
|
||
|
############-> Table "TMAIN" as "M4" Full Scan
|
||
|
"""
|
||
|
#---------------------------------------------------------
|
||
|
def replace_leading(source, char="#"):
|
||
|
stripped = source.lstrip()
|
||
|
return char * (len(source) - len(stripped)) + stripped
|
||
|
#---------------------------------------------------------
|
||
|
@pytest.mark.version('>=5.0,<6')
|
||
|
def test_1(act: Action, capsys):
|
||
|
with act.db.connect() as con:
|
||
|
cur = con.cursor()
|
||
|
for q in query_lst:
|
||
|
with cur.prepare(q) as ps:
|
||
|
print( '\n'.join([replace_leading(s) for s in ps.detailed_plan .split('\n')]) )
|
||
|
|
||
|
act.expected_stdout = expected_stdout
|
||
|
act.stdout = capsys.readouterr().out
|
||
|
assert act.clean_stdout == act.clean_expected_stdout
|