Re: [PR] [python] Introduce where for Python CLI table read [paimon]
JingsongLi merged PR #7389: URL: https://github.com/apache/paimon/pull/7389 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
plusplusjiajia commented on PR #7389: URL: https://github.com/apache/paimon/pull/7389#issuecomment-4028936939 LGTM, +1 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
JingsongLi commented on code in PR #7389:
URL: https://github.com/apache/paimon/pull/7389#discussion_r2909526251
##
paimon-python/pypaimon/cli/where_parser.py:
##
@@ -0,0 +1,359 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+SQL WHERE clause parser for Paimon CLI.
+
+Parses simple SQL-like WHERE expressions into Predicate objects.
+
+Supported operators:
+ =, !=, <>, <, <=, >, >=,
+ IS NULL, IS NOT NULL,
+ IN (...), NOT IN (...),
+ BETWEEN ... AND ...,
+ LIKE '...'
+
+Supported connectors: AND, OR (AND has higher precedence than OR).
+Parenthesized grouping is supported.
+
+Examples:
+ "age > 18"
+ "name = 'Alice' AND age >= 20"
+ "status IN ('active', 'pending')"
+ "score BETWEEN 60 AND 100"
+ "name LIKE 'A%'"
+ "deleted_at IS NULL"
+ "age > 18 OR (name = 'Bob' AND status = 'active')"
+"""
+
+import re
+from typing import Any, Dict, List, Optional
+
+from pypaimon.common.predicate import Predicate
+from pypaimon.common.predicate_builder import PredicateBuilder
+from pypaimon.schema.data_types import AtomicType, DataField
+
+
+def extract_fields_from_where(where_string: str, available_fields: set) -> set:
+"""Extract all field names referenced in a WHERE clause.
+
+Args:
+where_string: The WHERE clause string.
+available_fields: Set of valid field names from the table schema.
+
+Returns:
+A set of field names referenced in the WHERE clause.
+"""
+if not where_string or not where_string.strip():
+return set()
+
+tokens = _tokenize(where_string.strip())
+referenced_fields = set()
+for token in tokens:
+if token in available_fields:
+referenced_fields.add(token)
+return referenced_fields
+
+
+def parse_where_clause(where_string: str, fields: List[DataField]) ->
Optional[Predicate]:
+"""Parse a SQL-like WHERE clause string into a Predicate.
+
+Args:
+where_string: The WHERE clause string (without the 'WHERE' keyword).
+fields: The table schema fields for type resolution.
+
+Returns:
+A Predicate object, or None if the string is empty.
+
+Raises:
+ValueError: If the WHERE clause cannot be parsed.
+"""
+where_string = where_string.strip()
+if not where_string:
+return None
+
+field_type_map = _build_field_type_map(fields)
+predicate_builder = PredicateBuilder(fields)
+tokens = _tokenize(where_string)
+predicate, remaining = _parse_or_expression(tokens, predicate_builder,
field_type_map)
+
+if remaining:
+raise ValueError(
+f"Unexpected tokens after parsing: {' '.join(remaining)}"
+)
+
+return predicate
+
+
+def _build_field_type_map(fields: List[DataField]) -> Dict[str, str]:
+"""Build a mapping from field name to its base type string."""
+result = {}
+for field in fields:
+if isinstance(field.type, AtomicType):
+result[field.name] = field.type.type.upper()
+else:
+result[field.name] = str(field.type).upper()
+return result
+
+
+def _cast_literal(value_str: str, type_name: str) -> Any:
+"""Cast a literal string to the appropriate Python type based on the field
type."""
+integer_types = {'TINYINT', 'SMALLINT', 'INT', 'INTEGER', 'BIGINT'}
+float_types = {'FLOAT', 'DOUBLE'}
+
+base_type = type_name.split('(')[0].strip()
+
+if base_type in integer_types:
+return int(value_str)
+if base_type in float_types:
+return float(value_str)
+if base_type.startswith('DECIMAL') or base_type in ('DECIMAL', 'NUMERIC',
'DEC'):
+return float(value_str)
+if base_type == 'BOOLEAN':
+return value_str.lower() in ('true', '1', 'yes')
+return value_str
+
+
+_TOKEN_PATTERN = re.compile(
+r"""
+ '(?:[^'\\]|\\.)*' # single-quoted string
+| "(?:[^"\\]|\\.)*"# double-quoted string
+| <= # <=
+| >= # >=
+| <> # <>
+| != # !=
+| [=<>]# single-char operators
+| [(),]# punctuation
+| [^\s,()=<>!'"]+ # unquoted word / number
+""",
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
plusplusjiajia commented on code in PR #7389:
URL: https://github.com/apache/paimon/pull/7389#discussion_r2909492766
##
paimon-python/pypaimon/cli/where_parser.py:
##
@@ -0,0 +1,359 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+SQL WHERE clause parser for Paimon CLI.
+
+Parses simple SQL-like WHERE expressions into Predicate objects.
+
+Supported operators:
+ =, !=, <>, <, <=, >, >=,
+ IS NULL, IS NOT NULL,
+ IN (...), NOT IN (...),
+ BETWEEN ... AND ...,
+ LIKE '...'
+
+Supported connectors: AND, OR (AND has higher precedence than OR).
+Parenthesized grouping is supported.
+
+Examples:
+ "age > 18"
+ "name = 'Alice' AND age >= 20"
+ "status IN ('active', 'pending')"
+ "score BETWEEN 60 AND 100"
+ "name LIKE 'A%'"
+ "deleted_at IS NULL"
+ "age > 18 OR (name = 'Bob' AND status = 'active')"
+"""
+
+import re
+from typing import Any, Dict, List, Optional
+
+from pypaimon.common.predicate import Predicate
+from pypaimon.common.predicate_builder import PredicateBuilder
+from pypaimon.schema.data_types import AtomicType, DataField
+
+
+def extract_fields_from_where(where_string: str, available_fields: set) -> set:
+"""Extract all field names referenced in a WHERE clause.
+
+Args:
+where_string: The WHERE clause string.
+available_fields: Set of valid field names from the table schema.
+
+Returns:
+A set of field names referenced in the WHERE clause.
+"""
+if not where_string or not where_string.strip():
+return set()
+
+tokens = _tokenize(where_string.strip())
+referenced_fields = set()
+for token in tokens:
+if token in available_fields:
+referenced_fields.add(token)
+return referenced_fields
+
+
+def parse_where_clause(where_string: str, fields: List[DataField]) ->
Optional[Predicate]:
+"""Parse a SQL-like WHERE clause string into a Predicate.
+
+Args:
+where_string: The WHERE clause string (without the 'WHERE' keyword).
+fields: The table schema fields for type resolution.
+
+Returns:
+A Predicate object, or None if the string is empty.
+
+Raises:
+ValueError: If the WHERE clause cannot be parsed.
+"""
+where_string = where_string.strip()
+if not where_string:
+return None
+
+field_type_map = _build_field_type_map(fields)
+predicate_builder = PredicateBuilder(fields)
+tokens = _tokenize(where_string)
+predicate, remaining = _parse_or_expression(tokens, predicate_builder,
field_type_map)
+
+if remaining:
+raise ValueError(
+f"Unexpected tokens after parsing: {' '.join(remaining)}"
+)
+
+return predicate
+
+
+def _build_field_type_map(fields: List[DataField]) -> Dict[str, str]:
+"""Build a mapping from field name to its base type string."""
+result = {}
+for field in fields:
+if isinstance(field.type, AtomicType):
+result[field.name] = field.type.type.upper()
+else:
+result[field.name] = str(field.type).upper()
+return result
+
+
+def _cast_literal(value_str: str, type_name: str) -> Any:
+"""Cast a literal string to the appropriate Python type based on the field
type."""
+integer_types = {'TINYINT', 'SMALLINT', 'INT', 'INTEGER', 'BIGINT'}
+float_types = {'FLOAT', 'DOUBLE'}
+
+base_type = type_name.split('(')[0].strip()
+
+if base_type in integer_types:
+return int(value_str)
+if base_type in float_types:
+return float(value_str)
+if base_type.startswith('DECIMAL') or base_type in ('DECIMAL', 'NUMERIC',
'DEC'):
+return float(value_str)
+if base_type == 'BOOLEAN':
+return value_str.lower() in ('true', '1', 'yes')
+return value_str
+
+
+_TOKEN_PATTERN = re.compile(
+r"""
+ '(?:[^'\\]|\\.)*' # single-quoted string
+| "(?:[^"\\]|\\.)*"# double-quoted string
+| <= # <=
+| >= # >=
+| <> # <>
+| != # !=
+| [=<>]# single-char operators
+| [(),]# punctuation
+| [^\s,()=<>!'"]+ # unquoted word / number
+
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
Copilot commented on code in PR #7389:
URL: https://github.com/apache/paimon/pull/7389#discussion_r2909476656
##
docs/content/pypaimon/cli.md:
##
@@ -94,10 +95,53 @@ paimon table read mydb.users -l 50
# Read specific columns
paimon table read mydb.users -s id,name,age
-# Combine select and limit
-paimon table read mydb.users -s id,name -l 50
+# Filter with WHERE clause
+paimon table read mydb.users --where "age > 18"
+
+# Combine select, where, and limit
+paimon table read mydb.users -s id,name -w "age >= 20 AND city = 'Beijing'" -l
50
```
+**WHERE Operators**
+
+The `--where` option supports SQL-like filter expressions:
+
+| Operator | Example |
+|---|---|
+| `=`, `!=`, `<>` | `name = 'Alice'` |
+| `<`, `<=`, `>`, `>=` | `age > 18` |
+| `IS NULL`, `IS NOT NULL` | `deleted_at IS NULL` |
+| `IN (...)`, `NOT IN (...)` | `status IN ('active', 'pending')` |
+| `BETWEEN ... AND ...` | `age BETWEEN 20 AND 30` |
+| `LIKE` | `name LIKE 'A%'` |
Review Comment:
The `NOT BETWEEN` operator is supported by the parser (and tested in
`where_parser_test.py`) but is missing from the WHERE Operators table in the
documentation. Both `NOT IN` and `NOT BETWEEN` are useful operators that users
may want to know about. The table should include a row for `NOT BETWEEN ... AND
...` alongside the existing `BETWEEN ... AND ...` entry.
##
paimon-python/pypaimon/cli/cli_table.py:
##
@@ -63,21 +63,46 @@ def cmd_table_read(args):
# Build read pipeline
read_builder = table.new_read_builder()
-# Apply projection (select columns) if specified
+available_fields = set(field.name for field in table.table_schema.fields)
+
+# Parse select and where options
select_columns = args.select
+where_clause = args.where
+user_columns = None
+extra_where_columns = []
+
if select_columns:
# Parse column names (comma-separated)
-columns = [col.strip() for col in select_columns.split(',')]
-
+user_columns = [col.strip() for col in select_columns.split(',')]
+
# Validate that all columns exist in the table schema
-available_fields = set(field.name for field in
table.table_schema.fields)
-invalid_columns = [col for col in columns if col not in
available_fields]
-
+invalid_columns = [col for col in user_columns if col not in
available_fields]
if invalid_columns:
print(f"Error: Column(s) {invalid_columns} do not exist in table
'{table_identifier}'.", file=sys.stderr)
sys.exit(1)
-
-read_builder = read_builder.with_projection(columns)
+
+# When both select and where are specified, ensure where-referenced fields
+# are included in the projection so the filter can work correctly.
+if user_columns and where_clause:
+from pypaimon.cli.where_parser import extract_fields_from_where
+where_fields = extract_fields_from_where(where_clause,
available_fields)
+user_column_set = set(user_columns)
+extra_where_columns = [f for f in where_fields if f not in
user_column_set]
Review Comment:
`where_fields` is returned as a `set` from `extract_fields_from_where`, so
iterating over it to build `extra_where_columns` at line 90 gives a
non-deterministic ordering. This makes the `projection_columns` list (and thus
the projected `read_type`) non-deterministic when more than one
WHERE-referenced field is missing from the user's selection. Consistently
deterministic behavior (and especially correct predicate-index computation
after fixing the related index bug) requires that `extra_where_columns` have a
stable, reproducible order. Consider preserving the order from the table schema
instead, e.g., building it as `[f.name for f in table.table_schema.fields if
f.name not in user_column_set and f.name in where_fields]`.
##
paimon-python/pypaimon/cli/cli_table.py:
##
@@ -63,21 +63,46 @@ def cmd_table_read(args):
# Build read pipeline
read_builder = table.new_read_builder()
-# Apply projection (select columns) if specified
+available_fields = set(field.name for field in table.table_schema.fields)
+
+# Parse select and where options
select_columns = args.select
+where_clause = args.where
+user_columns = None
+extra_where_columns = []
+
if select_columns:
# Parse column names (comma-separated)
-columns = [col.strip() for col in select_columns.split(',')]
-
+user_columns = [col.strip() for col in select_columns.split(',')]
+
# Validate that all columns exist in the table schema
-available_fields = set(field.name for field in
table.table_schema.fields)
-invalid_columns = [col for col in columns if col not in
available_fields]
-
+invalid_columns = [col for col in user_columns if col not in
available_fields]
if invalid_columns:
print(f"Error: Colu
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
JingsongLi commented on code in PR #7389:
URL: https://github.com/apache/paimon/pull/7389#discussion_r2909461616
##
docs/content/pypaimon/cli.md:
##
@@ -94,10 +95,53 @@ paimon table read mydb.users -l 50
# Read specific columns
paimon table read mydb.users -s id,name,age
-# Combine select and limit
-paimon table read mydb.users -s id,name -l 50
+# Filter with WHERE clause
+paimon table read mydb.users --where "age > 18"
+
+# Combine select, where, and limit
+paimon table read mydb.users -s id,name -w "age >= 20 AND city = 'Beijing'" -l
50
```
+**WHERE Operators**
+
+The `--where` option supports SQL-like filter expressions:
+
+| Operator | Example |
+|---|---|
+| `=`, `!=`, `<>` | `name = 'Alice'` |
+| `<`, `<=`, `>`, `>=` | `age > 18` |
+| `IS NULL`, `IS NOT NULL` | `deleted_at IS NULL` |
+| `IN (...)`, `NOT IN (...)` | `status IN ('active', 'pending')` |
+| `BETWEEN ... AND ...` | `age BETWEEN 20 AND 30` |
Review Comment:
I do not document it, it is just supported by AI, but the application
scenarios are extremely rare
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
plusplusjiajia commented on code in PR #7389:
URL: https://github.com/apache/paimon/pull/7389#discussion_r2909454464
##
docs/content/pypaimon/cli.md:
##
@@ -94,10 +95,53 @@ paimon table read mydb.users -l 50
# Read specific columns
paimon table read mydb.users -s id,name,age
-# Combine select and limit
-paimon table read mydb.users -s id,name -l 50
+# Filter with WHERE clause
+paimon table read mydb.users --where "age > 18"
+
+# Combine select, where, and limit
+paimon table read mydb.users -s id,name -w "age >= 20 AND city = 'Beijing'" -l
50
```
+**WHERE Operators**
+
+The `--where` option supports SQL-like filter expressions:
+
+| Operator | Example |
+|---|---|
+| `=`, `!=`, `<>` | `name = 'Alice'` |
+| `<`, `<=`, `>`, `>=` | `age > 18` |
+| `IS NULL`, `IS NOT NULL` | `deleted_at IS NULL` |
+| `IN (...)`, `NOT IN (...)` | `status IN ('active', 'pending')` |
+| `BETWEEN ... AND ...` | `age BETWEEN 20 AND 30` |
Review Comment:
seems also support NOT BETWEEN
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
Copilot commented on code in PR #7389:
URL: https://github.com/apache/paimon/pull/7389#discussion_r2909420254
##
paimon-python/pypaimon/cli/where_parser.py:
##
@@ -0,0 +1,357 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+SQL WHERE clause parser for Paimon CLI.
+
+Parses simple SQL-like WHERE expressions into Predicate objects.
+
+Supported operators:
+ =, !=, <>, <, <=, >, >=,
+ IS NULL, IS NOT NULL,
+ IN (...), NOT IN (...),
+ BETWEEN ... AND ...,
+ LIKE '...'
+
+Supported connectors: AND, OR (AND has higher precedence than OR).
+Parenthesized grouping is supported.
+
+Examples:
+ "age > 18"
+ "name = 'Alice' AND age >= 20"
+ "status IN ('active', 'pending')"
+ "score BETWEEN 60 AND 100"
+ "name LIKE 'A%'"
+ "deleted_at IS NULL"
+ "age > 18 OR (name = 'Bob' AND status = 'active')"
+"""
+
+import re
+from typing import Any, Dict, List, Optional
+
+from pypaimon.common.predicate import Predicate
+from pypaimon.common.predicate_builder import PredicateBuilder
+from pypaimon.schema.data_types import AtomicType, DataField
+
+
+def extract_fields_from_where(where_string: str, available_fields: set) -> set:
+"""Extract all field names referenced in a WHERE clause.
+
+Args:
+where_string: The WHERE clause string.
+available_fields: Set of valid field names from the table schema.
+
+Returns:
+A set of field names referenced in the WHERE clause.
+"""
+if not where_string or not where_string.strip():
+return set()
+
+tokens = _tokenize(where_string.strip())
+referenced_fields = set()
+for token in tokens:
+if token in available_fields:
+referenced_fields.add(token)
+return referenced_fields
+
+
+def parse_where_clause(where_string: str, fields: List[DataField]) ->
Optional[Predicate]:
+"""Parse a SQL-like WHERE clause string into a Predicate.
+
+Args:
+where_string: The WHERE clause string (without the 'WHERE' keyword).
+fields: The table schema fields for type resolution.
+
+Returns:
+A Predicate object, or None if the string is empty.
+
+Raises:
+ValueError: If the WHERE clause cannot be parsed.
+"""
+where_string = where_string.strip()
+if not where_string:
+return None
+
+field_type_map = _build_field_type_map(fields)
+predicate_builder = PredicateBuilder(fields)
+tokens = _tokenize(where_string)
+predicate, remaining = _parse_or_expression(tokens, predicate_builder,
field_type_map)
+
+if remaining:
+raise ValueError(
+f"Unexpected tokens after parsing: {' '.join(remaining)}"
+)
+
+return predicate
+
+
+def _build_field_type_map(fields: List[DataField]) -> Dict[str, str]:
+"""Build a mapping from field name to its base type string."""
+result = {}
+for field in fields:
+if isinstance(field.type, AtomicType):
+result[field.name] = field.type.type.upper()
+else:
+result[field.name] = str(field.type).upper()
+return result
+
+
+def _cast_literal(value_str: str, type_name: str) -> Any:
+"""Cast a literal string to the appropriate Python type based on the field
type."""
+integer_types = {'TINYINT', 'SMALLINT', 'INT', 'INTEGER', 'BIGINT'}
+float_types = {'FLOAT', 'DOUBLE'}
+
+base_type = type_name.split('(')[0].strip()
+
+if base_type in integer_types:
+return int(value_str)
+if base_type in float_types:
+return float(value_str)
+if base_type.startswith('DECIMAL') or base_type in ('DECIMAL', 'NUMERIC',
'DEC'):
+return float(value_str)
+if base_type == 'BOOLEAN':
+return value_str.lower() in ('true', '1', 'yes')
+return value_str
+
+
+_TOKEN_PATTERN = re.compile(
+r"""
+ '(?:[^'\\]|\\.)*' # single-quoted string
+| "(?:[^"\\]|\\.)*"# double-quoted string
+| <= # <=
+| >= # >=
+| <> # <>
+| != # !=
+| [=<>]# single-char operators
+| [(),]# punctuation
+| [^\s,()=<>!'"]+ # unquoted word / number
+""",
+
Re: [PR] [python] Introduce where for Python CLI table read [paimon]
JingsongLi commented on PR #7389: URL: https://github.com/apache/paimon/pull/7389#issuecomment-4028751135 3.10 Passed in https://github.com/JingsongLi/paimon/actions/runs/22886340765/job/66399708840 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
[PR] [python] Introduce where for Python CLI table read [paimon]
JingsongLi opened a new pull request, #7389:
URL: https://github.com/apache/paimon/pull/7389
### Purpose
Read data from a Paimon table and display it in a tabular format.
```shell
paimon table read mydb.users
```
**Options:**
- `--select, -s`: Select specific columns to read (comma-separated)
- `--where, -w`: Filter condition in SQL-like syntax
- `--limit, -l`: Maximum number of results to display (default: 100)
**Examples:**
```shell
# Read with limit
paimon table read mydb.users -l 50
# Read specific columns
paimon table read mydb.users -s id,name,age
# Filter with WHERE clause
paimon table read mydb.users --where "age > 18"
# Combine select, where, and limit
paimon table read mydb.users -s id,name -w "age >= 20 AND city = 'Beijing'"
-l 50
```
**WHERE Operators**
The `--where` option supports SQL-like filter expressions:
| Operator | Example |
|---|---|
| `=`, `!=`, `<>` | `name = 'Alice'` |
| `<`, `<=`, `>`, `>=` | `age > 18` |
| `IS NULL`, `IS NOT NULL` | `deleted_at IS NULL` |
| `IN (...)`, `NOT IN (...)` | `status IN ('active', 'pending')` |
| `BETWEEN ... AND ...` | `age BETWEEN 20 AND 30` |
| `LIKE` | `name LIKE 'A%'` |
Multiple conditions can be combined with `AND` and `OR` (AND has higher
precedence). Parentheses are supported for grouping:
```shell
# AND condition
paimon table read mydb.users -w "age >= 20 AND age <= 30"
# OR condition
paimon table read mydb.users -w "city = 'Beijing' OR city = 'Shanghai'"
# Parenthesized grouping
paimon table read mydb.users -w "(age > 18 OR name = 'Bob') AND city =
'Beijing'"
# IN list
paimon table read mydb.users -w "city IN ('Beijing', 'Shanghai', 'Hangzhou')"
# BETWEEN
paimon table read mydb.users -w "age BETWEEN 25 AND 35"
# LIKE pattern
paimon table read mydb.users -w "name LIKE 'A%'"
# IS NULL / IS NOT NULL
paimon table read mydb.users -w "email IS NOT NULL"
```
Literal values are automatically cast to the appropriate Python type based
on the table schema (e.g., `INT` fields cast to `int`, `DOUBLE` to `float`).
Output:
```
idname age city
1 Alice 25 Beijing
2 Bob 30 Shanghai
3 Charlie 35 Guangzhou
4 David 28 Shenzhen
5 Eve 32 Hangzhou
```
### Tests
### API and Format
### Documentation
### Generative AI tooling
Claude 4.6 Opus
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
