Files
gti d21a9d1140 Add 'fiscal/' from commit '102ba84500dbd9655a0471288c3e278652593ca9'
git-subtree-dir: fiscal
git-subtree-mainline: d95165fc8f
git-subtree-split: 102ba84500
2026-09-29 14:43:23 -03:00

111 lines
3.0 KiB
Python

import pytest
from gti_discovery.read_only import validate_read_only
def test_accepts_and_normalizes_select_query():
assert validate_read_only(" SELECT * FROM RDB$DATABASE ; ") == (
"SELECT * FROM RDB$DATABASE"
)
def test_accepts_with_query():
sql = "WITH x AS (SELECT 1 AS n FROM RDB$DATABASE) SELECT n FROM x"
assert validate_read_only(sql) == sql
@pytest.mark.parametrize(
"sql",
[
"INSERT INTO X VALUES (1)",
"UPDATE X SET A=1",
"DELETE FROM X",
"CREATE TABLE X(A INT)",
"ALTER TABLE X ADD A INT",
"DROP TABLE X",
"TRUNCATE TABLE X",
"EXECUTE PROCEDURE P",
"WITH x AS (SELECT 1 FROM RDB$DATABASE) INSERT INTO X VALUES (1)",
],
)
def test_rejects_write_or_side_effect_sql(sql):
with pytest.raises(ValueError):
validate_read_only(sql)
@pytest.mark.parametrize(
"sql",
[
"SELECT 1 FROM RDB$DATABASE; SELECT 2 FROM RDB$DATABASE",
"SELECT 1 FROM RDB$DATABASE -- comment",
"SELECT 1 /* comment */ FROM RDB$DATABASE",
"",
"VACUUM TABLE X",
],
)
def test_rejects_multiple_statements_comments_and_non_queries(sql):
with pytest.raises(ValueError):
validate_read_only(sql)
@pytest.mark.parametrize(
"sql",
[
"SELECT * FROM SIDE_EFFECTING_PROC(1)",
"SELECT GEN_ID(MY_GENERATOR, 1) FROM RDB$DATABASE",
"SELECT NEXT VALUE FOR MY_GENERATOR FROM RDB$DATABASE",
"SELECT * FROM X WITH LOCK",
"SELECT * FROM X FOR UPDATE",
"SELECT * FROM PKG . SELECTABLE_PROC (1)",
],
)
def test_rejects_known_side_effecting_select_constructs(sql):
with pytest.raises(ValueError):
validate_read_only(sql)
@pytest.mark.parametrize(
"sql",
[
"SELECT IIF(RDB$SYSTEM_FLAG = 1, 'SYSTEM', 'USER') FROM RDB$RELATIONS",
"SELECT EXTRACT(YEAR FROM CURRENT_DATE) FROM RDB$DATABASE",
"SELECT COALESCE(RDB$RELATION_NAME, '') FROM RDB$RELATIONS",
],
)
def test_accepts_legitimate_firebird_read_only_expressions(sql):
assert validate_read_only(sql) == sql
@pytest.mark.parametrize(
"sql",
[
"SELECT EXECUTE(1) FROM RDB$DATABASE",
"SELECT GEN_ID(MY_GENERATOR, 1) FROM RDB$DATABASE",
"SELECT * FROM SELECTABLE_PROC(1)",
"SELECT * FROM PKG . SELECTABLE_PROC (1)",
"SELECT * FROM PKG\t.\tSELECTABLE_PROC\t(1)",
],
)
def test_rejects_explicit_unsafe_callable_forms(sql):
with pytest.raises(ValueError):
validate_read_only(sql)
@pytest.mark.parametrize(
"sql",
[
"SELECT SIDE_EFFECTING_UDF(ID) FROM X",
"SELECT PKG . SIDE_EFFECTING_UDF(ID) FROM X",
],
)
def test_rejects_unknown_callable_in_select_projection(sql):
with pytest.raises(ValueError, match="callable"):
validate_read_only(sql)
def test_normalization_does_not_change_quoted_literal_contents():
sql = " SELECT ' keep spaces ; -- text ' FROM RDB$DATABASE ; "
assert validate_read_only(sql) == (
"SELECT ' keep spaces ; -- text ' FROM RDB$DATABASE"
)