Source code for sqlspec.core.compiler

"""SQL compilation and caching.

Components:
    - CompiledSQL: Immutable compilation result
    - SQLProcessor: SQL compiler with caching
    - Parameter processing via ParameterProcessor
"""

import logging
from collections import OrderedDict
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any, Literal, final

import sqlglot
from mypy_extensions import mypyc_attr
from sqlglot import expressions as exp
from sqlglot.errors import ParseError

import sqlspec.exceptions
from sqlspec.core.parameters import (
    ParameterProcessor,
    ParameterProfile,
    structural_fingerprint,
    validate_parameter_alignment,
    value_fingerprint,
)
from sqlspec.core.parameters._processor import _make_cache_key_tuple
from sqlspec.utils.logging import get_logger, log_with_context
from sqlspec.utils.type_guards import get_value_attribute

if TYPE_CHECKING:
    from sqlspec.core.statement import StatementConfig


__all__ = (
    "CompiledSQL",
    "OperationProfile",
    "OperationType",
    "SQLProcessor",
    "is_copy_from_operation",
    "is_copy_operation",
    "is_copy_to_operation",
)

logger: "logging.Logger" = get_logger("sqlspec.core.compiler")
OperationType = Literal[
    "SELECT",
    "INSERT",
    "UPDATE",
    "DELETE",
    "COPY",
    "COPY_FROM",
    "COPY_TO",
    "EXECUTE",
    "SCRIPT",
    "DDL",
    "PRAGMA",
    "MERGE",
    "COMMAND",
]

OPERATION_TYPE_MAP: "dict[type[exp.Expr], OperationType]" = {
    # Queries
    exp.Select: "SELECT",
    exp.Union: "SELECT",
    exp.Except: "SELECT",
    exp.Intersect: "SELECT",
    exp.Summarize: "SELECT",  # DuckDB SUMMARIZE — returns rows
    # DML
    exp.Insert: "INSERT",
    exp.Update: "UPDATE",
    exp.Delete: "DELETE",
    exp.Merge: "MERGE",
    exp.LoadData: "INSERT",  # Hive LOAD DATA — ingests data into a table
    # DDL
    exp.Create: "DDL",
    exp.Drop: "DDL",
    exp.Alter: "DDL",
    exp.TruncateTable: "DDL",
    exp.Grant: "DDL",
    exp.Revoke: "DDL",
    exp.Comment: "DDL",
    # Procedure execution
    exp.Execute: "EXECUTE",  # TSQL EXEC/EXECUTE
    # Session / Admin
    exp.Pragma: "PRAGMA",
    exp.Command: "COMMAND",
    exp.Set: "COMMAND",
    exp.Show: "COMMAND",  # MySQL dialect
    exp.Describe: "COMMAND",
    exp.Use: "COMMAND",
    exp.Kill: "COMMAND",
    exp.Analyze: "COMMAND",
    exp.Install: "COMMAND",  # DuckDB
    exp.Attach: "COMMAND",  # DuckDB / SQLite
    # Transaction control — mapped to COMMAND for now; a dedicated "TRANSACTION"
    # OperationType could be added if downstream code needs to distinguish these.
    exp.Transaction: "COMMAND",
    exp.Commit: "COMMAND",
    exp.Rollback: "COMMAND",
}

COPY_OPERATION_TYPES: "tuple[OperationType, ...]" = ("COPY", "COPY_FROM", "COPY_TO")

COPY_FROM_OPERATION_TYPES: "tuple[OperationType, ...]" = ("COPY", "COPY_FROM")

COPY_TO_OPERATION_TYPES: "tuple[OperationType, ...]" = ("COPY_TO",)

ParseCacheEntry = tuple[exp.Expr | None, OperationType, tuple[bool, bool]]


def is_copy_operation(operation_type: "OperationType") -> bool:
    """Determine if the operation corresponds to any PostgreSQL COPY variant.

    Args:
        operation_type: Operation type detected by the compiler.

    Returns:
        True when the operation type represents COPY, COPY FROM, or COPY TO.
    """

    return operation_type in COPY_OPERATION_TYPES
def is_copy_from_operation(operation_type: "OperationType") -> bool: """Check if the operation streams data into the database using COPY. Args: operation_type: Operation type detected by the compiler. Returns: True for COPY operations that read from client input (COPY FROM). """ return operation_type in COPY_FROM_OPERATION_TYPES