1212 JSON_LINES_OUTPUT_FORMAT ,
1313 JSON_OUTPUT_FORMAT ,
1414)
15- from firebolt .utils .exception import FireboltError , ProgrammingError
15+ from firebolt .utils .exception import ConfigurationError , FireboltError , ProgrammingError
1616
1717if TYPE_CHECKING :
1818 from firebolt .common .statement_formatter import StatementFormatter
@@ -44,6 +44,7 @@ def create_execution_plan(
4444 skip_parsing : bool = False ,
4545 async_execution : bool = False ,
4646 streaming : bool = False ,
47+ bulk_insert : bool = False ,
4748 ) -> ExecutionPlan :
4849 """Create an execution plan for the given statement and parameters."""
4950
@@ -65,13 +66,32 @@ def create_execution_plan(
6566 skip_parsing : bool = False ,
6667 async_execution : bool = False ,
6768 streaming : bool = False ,
69+ bulk_insert : bool = False ,
6870 ) -> ExecutionPlan :
6971 """Create execution plan for fb_numeric parameter style."""
70- query_params = self ._build_fb_numeric_query_params (
71- parameters , streaming , async_execution
72- )
72+ if bulk_insert :
73+ # Validate bulk_insert requirements
74+ query_normalized = raw_query .lstrip ().lower ()
75+ if not query_normalized .startswith ("insert" ):
76+ raise ConfigurationError ("bulk_insert is only supported for INSERT statements" )
77+ if ";" in raw_query .strip ().rstrip (";" ):
78+ raise ConfigurationError ("bulk_insert does not support multi-statement queries" )
79+ if not parameters :
80+ raise ConfigurationError ("bulk_insert requires at least one parameter set" )
81+
82+ # Prepare bulk insert query and parameters
83+ processed_query , processed_params = self ._prepare_bulk_insert (raw_query , parameters )
84+ query_params = self ._build_fb_numeric_query_params (
85+ processed_params , streaming , async_execution , {"merge_prepared_statement_batches" : "true" }
86+ )
87+ else :
88+ processed_query = raw_query
89+ query_params = self ._build_fb_numeric_query_params (
90+ parameters , streaming , async_execution
91+ )
92+
7393 return ExecutionPlan (
74- queries = [raw_query ],
94+ queries = [processed_query ],
7595 query_params = query_params ,
7696 is_multi_statement = False ,
7797 async_execution = async_execution ,
@@ -83,6 +103,7 @@ def _build_fb_numeric_query_params(
83103 parameters : Sequence [Sequence [ParameterType ]],
84104 streaming : bool ,
85105 async_execution : bool ,
106+ extra_params : Optional [Dict [str , Any ]] = None ,
86107 ) -> Dict [str , Any ]:
87108 """Build query parameters for fb_numeric style."""
88109 param_list = parameters [0 ] if parameters else []
@@ -101,8 +122,35 @@ def _build_fb_numeric_query_params(
101122 query_params ["query_parameters" ] = json .dumps (query_parameters )
102123 if async_execution :
103124 query_params ["async" ] = True
125+ if extra_params :
126+ query_params .update (extra_params )
104127 return query_params
105128
129+ def _prepare_bulk_insert (
130+ self , query : str , parameters_seq : Sequence [Sequence [ParameterType ]]
131+ ) -> tuple [str , Sequence [Sequence [ParameterType ]]]:
132+ """Execute multiple INSERT queries as a single batch."""
133+ if not parameters_seq :
134+ raise ProgrammingError ("bulk_insert requires at least one parameter set" )
135+
136+ # For bulk insert, we need to create unique parameter names for each INSERT
137+ # Example: ($1, $2); ($3, $4); ($5, $6) instead of ($1, $2); ($1, $2); ($1, $2)
138+ queries = []
139+ param_offset = 0
140+ for param_set in parameters_seq :
141+ # Replace parameter placeholders with unique numbers
142+ modified_query = query
143+ for i in range (len (param_set )):
144+ old_param = f"${ i + 1 } "
145+ new_param = f"${ param_offset + i + 1 } "
146+ modified_query = modified_query .replace (old_param , new_param )
147+ queries .append (modified_query )
148+ param_offset += len (param_set )
149+
150+ combined_query = "; " .join (queries )
151+ parameters = [param for param_set in parameters_seq for param in param_set ]
152+ return combined_query , [parameters ]
153+
106154
107155class QmarkStatementPlanner (BaseStatementPlanner ):
108156 """Statement planner for qmark parameter style."""
@@ -114,8 +162,13 @@ def create_execution_plan(
114162 skip_parsing : bool = False ,
115163 async_execution : bool = False ,
116164 streaming : bool = False ,
165+ bulk_insert : bool = False ,
117166 ) -> ExecutionPlan :
118167 """Create execution plan for qmark parameter style."""
168+ # Validate bulk_insert is not used with qmark
169+ if bulk_insert :
170+ raise ConfigurationError ("bulk_insert is only supported for fb_numeric" )
171+
119172 queries : List [Union [SetParameter , str ]] = (
120173 [raw_query ]
121174 if skip_parsing
0 commit comments