1010from sqlspec .parameters .types import TypedParameter
1111from sqlspec .statement import SQLResult , Statement , StatementFilter
1212from sqlspec .statement .builder import QueryBuilder
13+ from sqlspec .statement .cache import get_cache_config , sql_cache
1314from sqlspec .statement .pipeline import SQLTransformContext , create_pipeline_from_config
1415from sqlspec .statement .result import OperationType
1516from sqlspec .statement .splitter import split_sql_script
1617from sqlspec .statement .sql import SQL , StatementConfig
1718from sqlspec .utils .logging import get_logger
19+ from sqlspec .utils .statement_hashing import hash_sql_statement
1820
1921if TYPE_CHECKING :
2022 from sqlspec .typing import StatementParameters
@@ -469,7 +471,7 @@ def _apply_pipeline_transformations(
469471 def _get_compiled_sql (
470472 self , statement : "SQL" , statement_config : "StatementConfig" , flatten_single_params : bool = False
471473 ) -> tuple [str , Any ]:
472- """Get compiled SQL with optimal parameter style (only converts when needed) .
474+ """Get compiled SQL with optimal parameter style and caching support .
473475
474476 Args:
475477 statement: SQL statement to compile
@@ -479,6 +481,26 @@ def _get_compiled_sql(
479481 Returns:
480482 Tuple of (compiled_sql, parameters)
481483 """
484+
485+ # Check if caching is enabled
486+ cache_config = get_cache_config ()
487+ cache_key = None
488+ if cache_config .compiled_cache_enabled and statement_config .enable_caching :
489+ # Generate cache key that includes parameter style context
490+ cache_key = self ._generate_compilation_cache_key (statement , statement_config , flatten_single_params )
491+
492+ # Try cache first
493+ cached_result = sql_cache .get (cache_key )
494+ if cached_result is not None :
495+ sql , params = cached_result
496+ # Apply driver parameter preparation to cached params
497+ prepared_params = self .prepare_driver_parameters (params , statement_config , is_many = statement .is_many )
498+ # Apply output_transformer if configured
499+ if statement_config .parameter_config .output_transformer :
500+ sql , prepared_params = statement_config .parameter_config .output_transformer (sql , prepared_params )
501+ return sql , prepared_params
502+
503+ # Determine target parameter style (existing logic)
482504 if statement .is_script and not statement_config .parameter_config .needs_static_script_compilation :
483505 target_style = ParameterStyle .STATIC
484506 elif statement_config .parameter_config .supported_execution_parameter_styles is not None :
@@ -496,7 +518,15 @@ def _get_compiled_sql(
496518 else :
497519 # No execution style configuration, use default parameter style for explicit compilation
498520 target_style = statement_config .parameter_config .default_parameter_style
521+
522+ # Compile the SQL
499523 sql , params = statement .compile (placeholder_style = target_style , flatten_single_params = flatten_single_params )
524+
525+ # Cache the compilation result if caching is enabled (before driver preparation)
526+ if cache_key is not None :
527+ sql_cache .set (cache_key , (sql , params ))
528+
529+ # Prepare parameters for driver
500530 prepared_params = self .prepare_driver_parameters (params , statement_config , is_many = statement .is_many )
501531
502532 # Apply output_transformer if configured
@@ -505,6 +535,32 @@ def _get_compiled_sql(
505535
506536 return sql , prepared_params
507537
538+ def _generate_compilation_cache_key (
539+ self , statement : "SQL" , config : "StatementConfig" , flatten_single_params : bool
540+ ) -> str :
541+ """Generate cache key that includes all compilation context.
542+
543+ This method creates a deterministic cache key that includes all factors
544+ that affect SQL compilation, preventing cache contamination between
545+ different compilation contexts.
546+ """
547+
548+ # Include all factors that affect compilation
549+ context_hash = hash (
550+ (
551+ config .parameter_config .hash (),
552+ config .dialect ,
553+ statement .is_script ,
554+ statement .is_many ,
555+ flatten_single_params ,
556+ bool (config .parameter_config .output_transformer ),
557+ bool (config .parameter_config .needs_static_script_compilation ),
558+ )
559+ )
560+
561+ base_hash = hash_sql_statement (statement )
562+ return f"compiled:{ base_hash } :{ context_hash } "
563+
508564 def _create_count_query (self , original_sql : "SQL" ) -> "SQL" :
509565 """Create a COUNT query from the original SQL statement.
510566
0 commit comments