sql-optimizer


Namesql-optimizer JSON
Version 1.0.3 PyPI version JSON
download
home_pagehttps://github.com/sql-optimizer/sql-optimizer-python
SummaryPython обертка для Java-оптимизатора SQL запросов на базе Apache Calcite
upload_time2025-08-23 23:37:01
maintainerNone
docs_urlNone
authorSQL Optimizer Team
requires_python>=3.8
licenseMIT
keywords sql optimizer calcite java database query optimization
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # SQL Optimizer Python Package

Python обертка для Java-оптимизатора SQL запросов на базе Apache Calcite.

## Возможности

- **Python API**: Простой в использовании Python интерфейс для оптимизации SQL
- **Java Backend**: Использует мощь Apache Calcite для оптимизации запросов
- **Поддержка метаданных**: Определение пользовательских схем таблиц и типов данных
- **Правила оптимизации**: Применение пользовательских стратегий оптимизации
- **CLI интерфейс**: Командная строка для быстрой оптимизации
- **Автономный пакет**: Включает Java JAR файл - не требует отдельной установки Java

## Требования

- Python 3.8 или выше
- Java 1.8 или выше (автоопределяется)

## Установка

### Из Wheel пакета

```bash
pip install sql-optimizer-1.0.0-py3-none-any.whl
```

### Из исходного кода

```bash
# Клонирование репозитория
git clone https://github.com/sql-optimizer/sql-optimizer-python.git
cd sql-optimizer-python

# Установка в режиме разработки
pip install -e .
```

## Quick Start

### Basic Usage

```python
from sql_optimizer_python import SqlOptimizer

# Initialize optimizer
optimizer = SqlOptimizer()

# Optimize a simple query
result = optimizer.optimize("SELECT * FROM employees")
print(result)
```

### With Custom Metadata

```python
# Define table metadata
metadata = {
    "custom_table": {
        "columns": {
            "id": {"type": "INTEGER"},
            "name": {"type": "VARCHAR"},
            "age": {"type": "INTEGER"}
        },
        "rowCount": 1000
    }
}

# Optimize with metadata
result = optimizer.optimize(
    "SELECT * FROM custom_table WHERE age > 25",
    metadata=metadata
)
```

### With Optimization Rules

```python
from sql_optimizer_python import OptimizationRule

# Create optimization rules
rules = [
    OptimizationRule(
        name="push_down_filter",
        description="Push filter operations down",
        priority=100,
        conditions=[{"type": "node_type", "operator": "contains", "value": "TableScan"}],
        transformations=[{"action": "push_down", "target": "filter", "cost_reduction": 25.0}]
    )
]

# Optimize with rules
result = optimizer.optimize(
    "SELECT * FROM employees WHERE salary > 50000",
    optimization_rules=rules
)
```

## Command Line Interface

### Basic Optimization

```bash
sql-optimizer "SELECT * FROM employees"
```

### With Metadata File

```bash
sql-optimizer "SELECT * FROM custom_table" --metadata-file examples/custom_table_metadata.json
```

### With Optimization Rules

```bash
sql-optimizer "SELECT * FROM employees" --rules-file examples/basic_optimization_rules.json
```

### Check Java Runtime

```bash
sql-optimizer --check-java
```

### Pretty Print Output

```bash
sql-optimizer "SELECT * FROM employees" --pretty
```

## API Reference

### SqlOptimizer

Main class for SQL query optimization.

```python
class SqlOptimizer:
    def __init__(self, java_home: Optional[str] = None)
    
    def optimize(self, sql_query: str, 
                metadata: Optional[Union[Dict, str]] = None,
                optimization_rules: Optional[Union[List[OptimizationRule], str]] = None,
                metadata_file: Optional[str] = None,
                rules_file: Optional[str] = None) -> Dict[str, Any]
    
    def optimize_from_files(self, sql_query: str, 
                          metadata_file: Optional[str] = None,
                          rules_file: Optional[str] = None) -> Dict[str, Any]
    
    def get_version(self) -> str
    def get_java_info(self) -> Dict[str, str]
```

### OptimizationRule

Represents an optimization rule.

```python
class OptimizationRule:
    def __init__(self, name: str, description: str, priority: int = 100, 
                 enabled: bool = True, conditions: Optional[List[Dict]] = None,
                 transformations: Optional[List[Dict]] = None, 
                 metadata: Optional[Dict] = None)
    
    def to_dict(self) -> Dict[str, Any]
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'OptimizationRule'
```

### OptimizationEngine

Manages optimization rules.

```python
class OptimizationEngine:
    def __init__(self)
    
    def add_rule(self, rule: OptimizationRule) -> None
    def add_rules_from_file(self, file_path: str) -> None
    def add_rules_from_json(self, rules_json: str) -> None
    def get_rules_json(self) -> str
    def clear_rules(self) -> None
```

## Metadata Format

Table metadata is defined in JSON format:

```json
{
  "table_name": {
    "columns": {
      "column_name": {
        "type": "INTEGER|VARCHAR|DOUBLE|BOOLEAN",
        "nullable": true|false
      }
    },
    "rowCount": 1000
  }
}
```

## Optimization Rules Format

Optimization rules are defined in JSON format:

```json
[
  {
    "name": "rule_name",
    "description": "Rule description",
    "priority": 100,
    "enabled": true,
    "conditions": [
      {
        "type": "node_type|table_name|cost_threshold|field_count",
        "operator": "equals|contains|greater_than|less_than",
        "value": "value",
        "negated": false
      }
    ],
    "transformations": [
      {
        "action": "push_down|reorder|optimize|prune|replace",
        "target": "filter|projection|join|scan|aggregate",
        "parameters": {},
        "cost_reduction": 25.0
      }
    ],
    "metadata": {
      "category": "filter_optimization",
      "author": "system"
    }
  }
]
```

## Output Format

The optimizer returns a JSON object with the following structure:

```json
{
  "originalQuery": "SELECT * FROM employees",
  "metadata": { /* table metadata if provided */ },
  "optimizedPlan": {
    "relType": "LogicalTableScan",
    "rowType": {
      "fieldCount": 4,
      "nullable": false,
      "fields": {
        "id": "INTEGER",
        "name": "VARCHAR",
        "department": "VARCHAR",
        "salary": "INTEGER"
      }
    },
    "cost": {
      "cpu": 101.0,
      "io": 0.0,
      "rows": 100.0,
      "infinite": false
    }
  },
  "optimizationStats": {
    "appliedRules": ["push_down_filter"],
    "totalRulesConsidered": 3,
    "optimizationDetails": {}
  },
  "explanation": "LogicalTableScan(table=[[TEST, employees]])"
}
```

## Examples

### Example 1: Basic Query Optimization

```python
from sql_optimizer_python import SqlOptimizer

optimizer = SqlOptimizer()
result = optimizer.optimize("SELECT * FROM employees WHERE salary > 50000")
print(result["optimizedPlan"]["relType"])
```

### Example 2: Custom Table with Metadata

```python
metadata = {
    "users": {
        "columns": {
            "id": {"type": "INTEGER"},
            "username": {"type": "VARCHAR"},
            "email": {"type": "VARCHAR"},
            "active": {"type": "BOOLEAN"}
        },
        "rowCount": 10000
    }
}

result = optimizer.optimize(
    "SELECT username, email FROM users WHERE active = true",
    metadata=metadata
)
```

### Example 3: Custom Optimization Rules

```python
from sql_optimizer_python import OptimizationRule

rules = [
    OptimizationRule(
        name="index_scan_optimization",
        description="Use index scan for large tables",
        priority=80,
        conditions=[
            {"type": "node_type", "operator": "equals", "value": "LogicalTableScan"},
            {"type": "cost_threshold", "operator": "greater_than", "value": 1000.0}
        ],
        transformations=[
            {"action": "optimize", "target": "scan", "cost_reduction": 50.0}
        ]
    )
]

result = optimizer.optimize(
    "SELECT * FROM large_table",
    optimization_rules=rules
)
```

## Error Handling

The package provides custom exceptions for different error types:

```python
from sql_optimizer_python import (
    SqlOptimizerError, JavaRuntimeError, OptimizationError, 
    MetadataError, RulesError
)

try:
    result = optimizer.optimize("SELECT * FROM table")
except JavaRuntimeError as e:
    print(f"Java runtime issue: {e}")
except OptimizationError as e:
    print(f"Optimization failed: {e}")
except MetadataError as e:
    print(f"Metadata error: {e}")
except RulesError as e:
    print(f"Rules error: {e}")
```

## Development

### Running Tests

```bash
pytest tests/
```

### Building Wheel

```bash
python setup.py bdist_wheel
```

### Installing in Development Mode

```bash
pip install -e .
```

## License

MIT License - see LICENSE file for details.

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Submit a pull request

## Support

- Documentation: https://sql-optimizer-python.readthedocs.io/
- Issues: https://github.com/sql-optimizer/sql-optimizer-python/issues
- Discussions: https://github.com/sql-optimizer/sql-optimizer-python/discussions

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/sql-optimizer/sql-optimizer-python",
    "name": "sql-optimizer",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "SQL Optimizer Team <team@sql-optimizer.com>",
    "keywords": "sql, optimizer, calcite, java, database, query, optimization",
    "author": "SQL Optimizer Team",
    "author_email": "SQL Optimizer Team <team@sql-optimizer.com>",
    "download_url": null,
    "platform": null,
    "description": "# SQL Optimizer Python Package\n\nPython \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f Java-\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0442\u043e\u0440\u0430 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430 \u0431\u0430\u0437\u0435 Apache Calcite.\n\n## \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\n\n- **Python API**: \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 Python \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 SQL\n- **Java Backend**: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043c\u043e\u0449\u044c Apache Calcite \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\n- **\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445**: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0441\u0445\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445\n- **\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438**: \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438\n- **CLI \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441**: \u041a\u043e\u043c\u0430\u043d\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0439 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438\n- **\u0410\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442**: \u0412\u043a\u043b\u044e\u0447\u0430\u0435\u0442 Java JAR \u0444\u0430\u0439\u043b - \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 Java\n\n## \u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\n\n- Python 3.8 \u0438\u043b\u0438 \u0432\u044b\u0448\u0435\n- Java 1.8 \u0438\u043b\u0438 \u0432\u044b\u0448\u0435 (\u0430\u0432\u0442\u043e\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f)\n\n## \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\n\n### \u0418\u0437 Wheel \u043f\u0430\u043a\u0435\u0442\u0430\n\n```bash\npip install sql-optimizer-1.0.0-py3-none-any.whl\n```\n\n### \u0418\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430\n\n```bash\n# \u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\ngit clone https://github.com/sql-optimizer/sql-optimizer-python.git\ncd sql-optimizer-python\n\n# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438\npip install -e .\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nfrom sql_optimizer_python import SqlOptimizer\n\n# Initialize optimizer\noptimizer = SqlOptimizer()\n\n# Optimize a simple query\nresult = optimizer.optimize(\"SELECT * FROM employees\")\nprint(result)\n```\n\n### With Custom Metadata\n\n```python\n# Define table metadata\nmetadata = {\n    \"custom_table\": {\n        \"columns\": {\n            \"id\": {\"type\": \"INTEGER\"},\n            \"name\": {\"type\": \"VARCHAR\"},\n            \"age\": {\"type\": \"INTEGER\"}\n        },\n        \"rowCount\": 1000\n    }\n}\n\n# Optimize with metadata\nresult = optimizer.optimize(\n    \"SELECT * FROM custom_table WHERE age > 25\",\n    metadata=metadata\n)\n```\n\n### With Optimization Rules\n\n```python\nfrom sql_optimizer_python import OptimizationRule\n\n# Create optimization rules\nrules = [\n    OptimizationRule(\n        name=\"push_down_filter\",\n        description=\"Push filter operations down\",\n        priority=100,\n        conditions=[{\"type\": \"node_type\", \"operator\": \"contains\", \"value\": \"TableScan\"}],\n        transformations=[{\"action\": \"push_down\", \"target\": \"filter\", \"cost_reduction\": 25.0}]\n    )\n]\n\n# Optimize with rules\nresult = optimizer.optimize(\n    \"SELECT * FROM employees WHERE salary > 50000\",\n    optimization_rules=rules\n)\n```\n\n## Command Line Interface\n\n### Basic Optimization\n\n```bash\nsql-optimizer \"SELECT * FROM employees\"\n```\n\n### With Metadata File\n\n```bash\nsql-optimizer \"SELECT * FROM custom_table\" --metadata-file examples/custom_table_metadata.json\n```\n\n### With Optimization Rules\n\n```bash\nsql-optimizer \"SELECT * FROM employees\" --rules-file examples/basic_optimization_rules.json\n```\n\n### Check Java Runtime\n\n```bash\nsql-optimizer --check-java\n```\n\n### Pretty Print Output\n\n```bash\nsql-optimizer \"SELECT * FROM employees\" --pretty\n```\n\n## API Reference\n\n### SqlOptimizer\n\nMain class for SQL query optimization.\n\n```python\nclass SqlOptimizer:\n    def __init__(self, java_home: Optional[str] = None)\n    \n    def optimize(self, sql_query: str, \n                metadata: Optional[Union[Dict, str]] = None,\n                optimization_rules: Optional[Union[List[OptimizationRule], str]] = None,\n                metadata_file: Optional[str] = None,\n                rules_file: Optional[str] = None) -> Dict[str, Any]\n    \n    def optimize_from_files(self, sql_query: str, \n                          metadata_file: Optional[str] = None,\n                          rules_file: Optional[str] = None) -> Dict[str, Any]\n    \n    def get_version(self) -> str\n    def get_java_info(self) -> Dict[str, str]\n```\n\n### OptimizationRule\n\nRepresents an optimization rule.\n\n```python\nclass OptimizationRule:\n    def __init__(self, name: str, description: str, priority: int = 100, \n                 enabled: bool = True, conditions: Optional[List[Dict]] = None,\n                 transformations: Optional[List[Dict]] = None, \n                 metadata: Optional[Dict] = None)\n    \n    def to_dict(self) -> Dict[str, Any]\n    @classmethod\n    def from_dict(cls, data: Dict[str, Any]) -> 'OptimizationRule'\n```\n\n### OptimizationEngine\n\nManages optimization rules.\n\n```python\nclass OptimizationEngine:\n    def __init__(self)\n    \n    def add_rule(self, rule: OptimizationRule) -> None\n    def add_rules_from_file(self, file_path: str) -> None\n    def add_rules_from_json(self, rules_json: str) -> None\n    def get_rules_json(self) -> str\n    def clear_rules(self) -> None\n```\n\n## Metadata Format\n\nTable metadata is defined in JSON format:\n\n```json\n{\n  \"table_name\": {\n    \"columns\": {\n      \"column_name\": {\n        \"type\": \"INTEGER|VARCHAR|DOUBLE|BOOLEAN\",\n        \"nullable\": true|false\n      }\n    },\n    \"rowCount\": 1000\n  }\n}\n```\n\n## Optimization Rules Format\n\nOptimization rules are defined in JSON format:\n\n```json\n[\n  {\n    \"name\": \"rule_name\",\n    \"description\": \"Rule description\",\n    \"priority\": 100,\n    \"enabled\": true,\n    \"conditions\": [\n      {\n        \"type\": \"node_type|table_name|cost_threshold|field_count\",\n        \"operator\": \"equals|contains|greater_than|less_than\",\n        \"value\": \"value\",\n        \"negated\": false\n      }\n    ],\n    \"transformations\": [\n      {\n        \"action\": \"push_down|reorder|optimize|prune|replace\",\n        \"target\": \"filter|projection|join|scan|aggregate\",\n        \"parameters\": {},\n        \"cost_reduction\": 25.0\n      }\n    ],\n    \"metadata\": {\n      \"category\": \"filter_optimization\",\n      \"author\": \"system\"\n    }\n  }\n]\n```\n\n## Output Format\n\nThe optimizer returns a JSON object with the following structure:\n\n```json\n{\n  \"originalQuery\": \"SELECT * FROM employees\",\n  \"metadata\": { /* table metadata if provided */ },\n  \"optimizedPlan\": {\n    \"relType\": \"LogicalTableScan\",\n    \"rowType\": {\n      \"fieldCount\": 4,\n      \"nullable\": false,\n      \"fields\": {\n        \"id\": \"INTEGER\",\n        \"name\": \"VARCHAR\",\n        \"department\": \"VARCHAR\",\n        \"salary\": \"INTEGER\"\n      }\n    },\n    \"cost\": {\n      \"cpu\": 101.0,\n      \"io\": 0.0,\n      \"rows\": 100.0,\n      \"infinite\": false\n    }\n  },\n  \"optimizationStats\": {\n    \"appliedRules\": [\"push_down_filter\"],\n    \"totalRulesConsidered\": 3,\n    \"optimizationDetails\": {}\n  },\n  \"explanation\": \"LogicalTableScan(table=[[TEST, employees]])\"\n}\n```\n\n## Examples\n\n### Example 1: Basic Query Optimization\n\n```python\nfrom sql_optimizer_python import SqlOptimizer\n\noptimizer = SqlOptimizer()\nresult = optimizer.optimize(\"SELECT * FROM employees WHERE salary > 50000\")\nprint(result[\"optimizedPlan\"][\"relType\"])\n```\n\n### Example 2: Custom Table with Metadata\n\n```python\nmetadata = {\n    \"users\": {\n        \"columns\": {\n            \"id\": {\"type\": \"INTEGER\"},\n            \"username\": {\"type\": \"VARCHAR\"},\n            \"email\": {\"type\": \"VARCHAR\"},\n            \"active\": {\"type\": \"BOOLEAN\"}\n        },\n        \"rowCount\": 10000\n    }\n}\n\nresult = optimizer.optimize(\n    \"SELECT username, email FROM users WHERE active = true\",\n    metadata=metadata\n)\n```\n\n### Example 3: Custom Optimization Rules\n\n```python\nfrom sql_optimizer_python import OptimizationRule\n\nrules = [\n    OptimizationRule(\n        name=\"index_scan_optimization\",\n        description=\"Use index scan for large tables\",\n        priority=80,\n        conditions=[\n            {\"type\": \"node_type\", \"operator\": \"equals\", \"value\": \"LogicalTableScan\"},\n            {\"type\": \"cost_threshold\", \"operator\": \"greater_than\", \"value\": 1000.0}\n        ],\n        transformations=[\n            {\"action\": \"optimize\", \"target\": \"scan\", \"cost_reduction\": 50.0}\n        ]\n    )\n]\n\nresult = optimizer.optimize(\n    \"SELECT * FROM large_table\",\n    optimization_rules=rules\n)\n```\n\n## Error Handling\n\nThe package provides custom exceptions for different error types:\n\n```python\nfrom sql_optimizer_python import (\n    SqlOptimizerError, JavaRuntimeError, OptimizationError, \n    MetadataError, RulesError\n)\n\ntry:\n    result = optimizer.optimize(\"SELECT * FROM table\")\nexcept JavaRuntimeError as e:\n    print(f\"Java runtime issue: {e}\")\nexcept OptimizationError as e:\n    print(f\"Optimization failed: {e}\")\nexcept MetadataError as e:\n    print(f\"Metadata error: {e}\")\nexcept RulesError as e:\n    print(f\"Rules error: {e}\")\n```\n\n## Development\n\n### Running Tests\n\n```bash\npytest tests/\n```\n\n### Building Wheel\n\n```bash\npython setup.py bdist_wheel\n```\n\n### Installing in Development Mode\n\n```bash\npip install -e .\n```\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests\n5. Submit a pull request\n\n## Support\n\n- Documentation: https://sql-optimizer-python.readthedocs.io/\n- Issues: https://github.com/sql-optimizer/sql-optimizer-python/issues\n- Discussions: https://github.com/sql-optimizer/sql-optimizer-python/discussions\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f Java-\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0442\u043e\u0440\u0430 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430 \u0431\u0430\u0437\u0435 Apache Calcite",
    "version": "1.0.3",
    "project_urls": {
        "Bug Tracker": "https://github.com/sql-optimizer/sql-optimizer-python/issues",
        "Documentation": "https://sql-optimizer-python.readthedocs.io/",
        "Homepage": "https://github.com/sql-optimizer/sql-optimizer-python",
        "Repository": "https://github.com/sql-optimizer/sql-optimizer-python"
    },
    "split_keywords": [
        "sql",
        " optimizer",
        " calcite",
        " java",
        " database",
        " query",
        " optimization"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "cda7d2556d1c30695828feda433c9aa29281d562072009e819e7a10b569821c1",
                "md5": "11eed3597e949b44498028b0a5b0b6ca",
                "sha256": "07c16a9fa9741a2a5a14160587924de8f4009ea0c68953dcdee73a07c75322c9"
            },
            "downloads": -1,
            "filename": "sql_optimizer-1.0.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "11eed3597e949b44498028b0a5b0b6ca",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 18606576,
            "upload_time": "2025-08-23T23:37:01",
            "upload_time_iso_8601": "2025-08-23T23:37:01.752529Z",
            "url": "https://files.pythonhosted.org/packages/cd/a7/d2556d1c30695828feda433c9aa29281d562072009e819e7a10b569821c1/sql_optimizer-1.0.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-23 23:37:01",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "sql-optimizer",
    "github_project": "sql-optimizer-python",
    "github_not_found": true,
    "lcname": "sql-optimizer"
}
        
Elapsed time: 1.40371s