Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ res = chdb.query('select * from file("data.csv", CSV)', 'CSV'); print(res)
print(f"SQL read {res.rows_read()} rows, {res.bytes_read()} bytes, elapsed {res.elapsed()} seconds")
```

### 参数化查询
```python
import chdb

df = chdb.query(
"SELECT toDate({base_date:String}) + number AS date "
"FROM numbers({total_days:UInt64}) "
"LIMIT {items_per_page:UInt64}",
"DataFrame",
params={"base_date": "2025-01-01", "total_days": 10, "items_per_page": 2},
)
print(df)
# date
# 0 2025-01-01
# 1 2025-01-02
```

更多内容请参见:
* [ClickHouse SQL语法: 定义和使用查询参数](https://clickhouse.com/docs/sql-reference/syntax#defining-and-using-query-parameters)
* [ClickHouse中如何使用参数化查询](https://clickhouse.com/videos/how-to-use-query-parameters-in-clickhouse)

### Pandas DataFrame 输出
```python
# 更多内容请参见 https://clickhouse.com/docs/en/interfaces/formats
Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,27 @@ res = chdb.query('select * from file("data.csv", CSV)', 'CSV'); print(res)
print(f"SQL read {res.rows_read()} rows, {res.bytes_read()} bytes, storage read {res.storage_rows_read()} rows, {res.storage_bytes_read()} bytes, elapsed {res.elapsed()} seconds")
```

### Parameterized queries
```python
import chdb

df = chdb.query(
"SELECT toDate({base_date:String}) + number AS date "
"FROM numbers({total_days:UInt64}) "
"LIMIT {items_per_page:UInt64}",
"DataFrame",
params={"base_date": "2025-01-01", "total_days": 10, "items_per_page": 2},
)
print(df)
# date
# 0 2025-01-01
# 1 2025-01-02
```

For more details, see:
* [ClickHouse SQL syntax: defining and using query parameters](https://clickhouse.com/docs/sql-reference/syntax#defining-and-using-query-parameters)
* [How to Use Query Parameters in ClickHouse](https://clickhouse.com/videos/how-to-use-query-parameters-in-clickhouse)

### Pandas dataframe output
```python
# See more in https://clickhouse.com/docs/en/interfaces/formats
Expand Down
9 changes: 6 additions & 3 deletions chdb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def to_arrowTable(res):


# wrap _chdb functions
def query(sql, output_format="CSV", path="", udf_path=""):
def query(sql, output_format="CSV", path="", udf_path="", params=None):
"""Execute SQL query using chDB engine.

This is the main query function that executes SQL statements using the embedded
Expand All @@ -135,6 +135,8 @@ def query(sql, output_format="CSV", path="", udf_path=""):
path (str, optional): Database file path. Defaults to "" (in-memory database).
Can be a file path or ":memory:" for in-memory database.
udf_path (str, optional): Path to User-Defined Functions directory. Defaults to "".
params (dict, optional): Named query parameters matching placeholders like ``{key:Type}``.
Values are converted to strings and passed to the engine without manual escaping.

Returns:
Query result in the specified format:
Expand Down Expand Up @@ -167,6 +169,7 @@ def query(sql, output_format="CSV", path="", udf_path=""):
>>> result = chdb.query("SELECT my_udf('test')", udf_path="/path/to/udfs")
"""
global g_udf_path
params = params or {}
if udf_path != "":
g_udf_path = udf_path
conn_str = ""
Expand Down Expand Up @@ -195,11 +198,11 @@ def query(sql, output_format="CSV", path="", udf_path=""):
conn = _chdb.connect(conn_str)

if lower_output_format == "dataframe":
res = conn.query_df(sql)
res = conn.query_df(sql, params=params)
conn.close()
return res

res = conn.query(sql, output_format)
res = conn.query(sql, output_format, params=params)

if res.has_error():
conn.close()
Expand Down
18 changes: 14 additions & 4 deletions chdb/session/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def cleanup(self):
except: # noqa
pass

def query(self, sql, fmt="CSV", udf_path=""):
def query(self, sql, fmt="CSV", udf_path="", params=None):
"""Execute a SQL query and return the results.

This method executes a SQL query against the session's database and returns
Expand All @@ -138,9 +138,14 @@ def query(self, sql, fmt="CSV", udf_path=""):
- "JSONCompact" - Compact JSON format
- "Arrow" - Apache Arrow format
- "Parquet" - Parquet format
- "DataFrame" - Pandas DataFrame
- "ArrowTable" - PyArrow Table

udf_path (str, optional): Path to user-defined functions. Defaults to "".
If not specified, uses the UDF path from session initialization.
params (dict, optional): Named parameters for ``{name:Type}`` placeholders.
Values must be compatible with the declared ClickHouse type; otherwise
query execution raises a RuntimeError.

Returns:
Query results in the specified format. The exact return type depends on
Expand Down Expand Up @@ -197,12 +202,12 @@ def query(self, sql, fmt="CSV", udf_path=""):
Eg: conn = connect(f"db_path?verbose&log-level=test")"""
)
fmt = "CSV"
return self._conn.query(sql, fmt)
return self._conn.query(sql, fmt, params=params)

# alias sql = query
sql = query

def send_query(self, sql, fmt="CSV") -> StreamingResult:
def send_query(self, sql, fmt="CSV", params=None) -> StreamingResult:
"""Execute a SQL query and return a streaming result iterator.

This method executes a SQL query against the session's database and returns
Expand All @@ -221,6 +226,11 @@ def send_query(self, sql, fmt="CSV") -> StreamingResult:
- "JSONCompact" - Compact JSON format
- "Arrow" - Apache Arrow format
- "Parquet" - Parquet format
- "DataFrame" - Pandas DataFrame
- "ArrowTable" - PyArrow Table
params (dict, optional): Named parameters for ``{name:Type}`` placeholders.
Type mismatches or missing required parameters propagate as RuntimeError
when fetching from the stream.

Returns:
StreamingResult: A streaming result iterator that yields query results
Expand Down Expand Up @@ -270,4 +280,4 @@ def send_query(self, sql, fmt="CSV") -> StreamingResult:
Eg: conn = connect(f"db_path?verbose&log-level=test")"""
)
fmt = "CSV"
return self._conn.send_query(sql, fmt)
return self._conn.send_query(sql, fmt, params=params)
10 changes: 5 additions & 5 deletions chdb/state/sqlitelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def cursor(self) -> "Cursor":
self._cursor = Cursor(self._conn)
return self._cursor

def query(self, query: str, format: str = "CSV") -> Any:
def query(self, query: str, format: str = "CSV", params=None) -> Any:
"""Execute a SQL query and return the complete results.

This method executes a SQL query synchronously and returns the complete
Expand Down Expand Up @@ -461,12 +461,12 @@ def query(self, query: str, format: str = "CSV") -> Any:
format = "Arrow"

if lower_output_format == "dataframe":
result = self._conn.query_df(query)
result = self._conn.query_df(query, params=params or {})
else:
result = self._conn.query(query, format)
result = self._conn.query(query, format, params=params or {})
return result_func(result)

def send_query(self, query: str, format: str = "CSV") -> StreamingResult:
def send_query(self, query: str, format: str = "CSV", params=None) -> StreamingResult:
"""Execute a SQL query and return a streaming result iterator.

This method executes a SQL query and returns a StreamingResult object
Expand Down Expand Up @@ -531,7 +531,7 @@ def send_query(self, query: str, format: str = "CSV") -> StreamingResult:
if lower_output_format in _arrow_format:
format = "Arrow"

c_stream_result = self._conn.send_query(query, format)
c_stream_result = self._conn.send_query(query, format, params=params or {})
is_dataframe = lower_output_format == "dataframe"
return StreamingResult(c_stream_result, self._conn, result_func, supports_record_batch, is_dataframe)

Expand Down
16 changes: 16 additions & 0 deletions programs/local/ChdbClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,22 @@ size_t ChdbClient::getStorageBytesRead() const
}

#if USE_PYTHON
void ChdbClient::setQueryParameters(const NameToNameMap & params)
{
std::lock_guard<std::mutex> lock(client_mutex);
query_parameters = params;
if (client_context)
client_context->setQueryParameters(query_parameters);
}

void ChdbClient::clearQueryParameters()
{
std::lock_guard<std::mutex> lock(client_mutex);
query_parameters.clear();
if (client_context)
client_context->setQueryParameters(query_parameters);
}

void ChdbClient::findQueryableObjFromPyCache(const String & query_str) const
{
python_table_cache->findQueryableObjFromQuery(query_str);
Expand Down
4 changes: 4 additions & 0 deletions programs/local/ChdbClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <Client/LocalConnection.h>
#include <Interpreters/Session.h>
#include <Common/Config/ConfigProcessor.h>
#include <Core/Names.h>
#include "QueryResult.h"

#include <memory>
Expand Down Expand Up @@ -44,6 +45,9 @@ class ChdbClient : public ClientBase
size_t getStorageBytesRead() const;

#if USE_PYTHON
void setQueryParameters(const NameToNameMap & params);
void clearQueryParameters();

void findQueryableObjFromPyCache(const String & query_str) const;
#endif

Expand Down
Loading