diff --git a/ibis-server/tests/routers/v3/connector/postgres/test_query.py b/ibis-server/tests/routers/v3/connector/postgres/test_query.py index f9fd53d24..c05cf5817 100644 --- a/ibis-server/tests/routers/v3/connector/postgres/test_query.py +++ b/ibis-server/tests/routers/v3/connector/postgres/test_query.py @@ -1219,3 +1219,46 @@ async def test_query_unicode_table(client, connection_info): "欄位1": "int32", "欄位2": "int32", } + + +async def test_case_sensitive_without_quote(client, connection_info): + manifest = { + "catalog": "wren", + "schema": "public", + "models": [ + { + "name": "Orders", + "tableReference": { + "schema": "public", + "table": "orders", + }, + "columns": [ + { + "name": "O_orderkey", + "type": "integer", + "expression": "o_orderkey", + }, + {"name": "O_custkey", "type": "integer", "expression": "o_custkey"}, + ], + } + ], + } + + manifest_str = base64.b64encode(orjson.dumps(manifest)).decode("utf-8") + + response = await client.post( + url=f"{base_url}/query?cacheEnable=true", + json={ + "connectionInfo": connection_info, + "manifestStr": manifest_str, + "sql": "SELECT O_orderkey, O_custkey FROM Orders LIMIT 1", + }, + headers={X_WREN_FALLBACK_DISABLE: "true"}, + ) + + assert response.status_code == 200 + result = response.json() + assert result["dtypes"] == { + "O_orderkey": "int32", + "O_custkey": "int32", + } diff --git a/wren-core-py/poetry.lock b/wren-core-py/poetry.lock index fea17865e..a543ec2ed 100644 --- a/wren-core-py/poetry.lock +++ b/wren-core-py/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "colorama" @@ -6,8 +6,6 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] -markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -19,7 +17,6 @@ version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, @@ -31,7 +28,6 @@ version = "1.9.0" description = "Build and publish crates with pyo3, cffi and uniffi bindings as well as rust binaries as python packages" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "maturin-1.9.0-py3-none-linux_armv6l.whl", hash = "sha256:18d77e395f62a0227697098526be6becb3ceea34a79f338b1b716fb96e42a1b2"}, {file = "maturin-1.9.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:33f046f52327b68c28203efe5ecc4fd1952b4d1fe34e65853092e3347a6a6fa0"}, @@ -54,42 +50,39 @@ zig = ["ziglang (>=0.10.0,<0.13.0)"] [[package]] name = "packaging" -version = "24.2" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] name = "pluggy" -version = "1.5.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" -groups = ["dev"] +python-versions = ">=3.9" files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ - {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, - {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] @@ -101,7 +94,6 @@ version = "8.4.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, @@ -123,7 +115,6 @@ version = "0.12.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848"}, {file = "ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6"}, @@ -146,6 +137,6 @@ files = [ ] [metadata] -lock-version = "2.1" +lock-version = "2.0" python-versions = ">=3.11,<3.12" content-hash = "ca7253dee98d2b2918039604cbe754db9d6d0bc47946c853c3e322677705d6e5" diff --git a/wren-core-py/src/extractor.rs b/wren-core-py/src/extractor.rs index 7d2906e70..1ab4d961d 100644 --- a/wren-core-py/src/extractor.rs +++ b/wren-core-py/src/extractor.rs @@ -43,7 +43,9 @@ impl PyManifestExtractor { } fn resolve_used_table_names(mdl: &WrenMDL, sql: &str) -> Result, CoreError> { - let ctx_state = wren_core::SessionContext::new().state(); + let mut config = wren_core::SessionConfig::new(); + config.options_mut().sql_parser.enable_ident_normalization = false; + let ctx_state = wren_core::SessionContext::new_with_config(config).state(); ctx_state .sql_to_statement(sql, "generic") .map_err(CoreError::from) diff --git a/wren-core-py/tests/test_modeling_core.py b/wren-core-py/tests/test_modeling_core.py index 1a06a4f5f..c0155365d 100644 --- a/wren-core-py/tests/test_modeling_core.py +++ b/wren-core-py/tests/test_modeling_core.py @@ -549,3 +549,42 @@ def test_backward_compatible_check(): json.dumps(manifest_backward).encode("utf-8") ).decode("utf-8") assert is_backward_compatible(manifest_backward_str) + + +def test_case_sensitive_without_quote(): + manifest = { + "catalog": "my_catalog", + "schema": "my_schema", + "dataSource": "mysql", + "models": [ + { + "name": "Orders", + "tableReference": { + "schema": "main", + "table": "orders", + }, + "columns": [ + {"name": "O_orderkey", "type": "integer"}, + {"name": "O_custkey", "type": "integer"}, + {"name": "O_orderdate", "type": "date"}, + ], + }, + ], + } + manifest_str = base64.b64encode(json.dumps(manifest).encode("utf-8")).decode( + "utf-8" + ) + sql = "select O_orderkey, O_custkey, O_orderdate from Orders" + extractor = ManifestExtractor(manifest_str) + tables = extractor.resolve_used_table_names(sql) + assert tables == ["Orders"] + + extracted_manifest = extractor.extract_by(tables) + encoded_str = to_json_base64(extracted_manifest) + + session_context = SessionContext(encoded_str, None) + actual = session_context.transform_sql(sql) + assert ( + actual + == 'SELECT "Orders"."O_orderkey", "Orders"."O_custkey", "Orders"."O_orderdate" FROM (SELECT "Orders"."O_custkey", "Orders"."O_orderdate", "Orders"."O_orderkey" FROM (SELECT __source."O_custkey" AS "O_custkey", __source."O_orderdate" AS "O_orderdate", __source."O_orderkey" AS "O_orderkey" FROM main.orders AS __source) AS "Orders") AS "Orders"' + )