@@ -1043,6 +1043,143 @@ def test_empty_sql_parameter(self):
10431043 with pytest .raises (ValueError , match = "List of SQL statements is empty" ):
10441044 hook .run (sql = empty_statement )
10451045
1046+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1047+ def test_run_multi_statement_with_split_statements_false (self , mock_conn ):
1048+ """When split_statements=False, cursor.execute() receives num_statements=0."""
1049+ hook = SnowflakeHook ()
1050+ conn = mock_conn .return_value
1051+ cur = mock .MagicMock (rowcount = 0 )
1052+ conn .cursor .return_value = cur
1053+ type(cur ).sfqid = mock .PropertyMock (return_value = "multi_query_id" )
1054+
1055+ sql = "BEGIN; CREATE TABLE t(id INT); INSERT INTO t VALUES(1); COMMIT;"
1056+ hook .run (sql , split_statements = False )
1057+
1058+ # Entire SQL block sent as one execute with num_statements=0
1059+ cur .execute .assert_called_once_with (
1060+ "BEGIN; CREATE TABLE t(id INT); INSERT INTO t VALUES(1); COMMIT" ,
1061+ num_statements = 0 ,
1062+ )
1063+ assert hook .query_ids == ["multi_query_id" ]
1064+
1065+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1066+ def test_run_split_statements_true_does_not_pass_num_statements (self , mock_conn ):
1067+ """When split_statements=True, cursor.execute() does not receive num_statements."""
1068+ hook = SnowflakeHook ()
1069+ conn = mock_conn .return_value
1070+ cur = mock .MagicMock (rowcount = 0 )
1071+ conn .cursor .return_value = cur
1072+ type(cur ).sfqid = mock .PropertyMock (side_effect = ["id1" , "id2" ])
1073+
1074+ hook .run ("SELECT 1; SELECT 2" , split_statements = True )
1075+
1076+ assert cur .execute .call_count == 2
1077+ for call in cur .execute .call_args_list :
1078+ assert "num_statements" not in call .kwargs
1079+
1080+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1081+ def test_run_sql_list_does_not_pass_num_statements (self , mock_conn ):
1082+ """When sql is a list, cursor.execute() does not receive num_statements."""
1083+ hook = SnowflakeHook ()
1084+ conn = mock_conn .return_value
1085+ cur = mock .MagicMock (rowcount = 0 )
1086+ conn .cursor .return_value = cur
1087+ type(cur ).sfqid = mock .PropertyMock (side_effect = ["id1" , "id2" ])
1088+
1089+ hook .run (["SELECT 1;" , "SELECT 2;" ])
1090+
1091+ assert cur .execute .call_count == 2
1092+ for call in cur .execute .call_args_list :
1093+ assert "num_statements" not in call .kwargs
1094+
1095+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1096+ def test_run_respects_autocommit_session_parameter (self , mock_conn ):
1097+ """When session_parameters has AUTOCOMMIT, set_autocommit is skipped and no commit."""
1098+ connection_kwargs = deepcopy (BASE_CONNECTION_KWARGS )
1099+ connection_kwargs ["extra" ]["session_parameters" ] = {"AUTOCOMMIT" : True }
1100+ with mock .patch .dict (
1101+ "os.environ" ,
1102+ AIRFLOW_CONN_SNOWFLAKE_DEFAULT = Connection (** connection_kwargs ).get_uri (),
1103+ ):
1104+ hook = SnowflakeHook ()
1105+ conn = mock_conn .return_value
1106+ cur = mock .MagicMock (rowcount = 0 )
1107+ conn .cursor .return_value = cur
1108+ type(cur ).sfqid = mock .PropertyMock (return_value = "qid" )
1109+
1110+ hook .run ("SELECT 1" , autocommit = False )
1111+
1112+ # set_autocommit should NOT have been called
1113+ conn .autocommit .assert_not_called ()
1114+ # No manual commit since AUTOCOMMIT session param is in effect
1115+ conn .commit .assert_not_called ()
1116+
1117+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1118+ def test_run_respects_autocommit_session_parameter_case_insensitive (self , mock_conn ):
1119+ """AUTOCOMMIT check is case-insensitive (Snowflake params are case-insensitive)."""
1120+ connection_kwargs = deepcopy (BASE_CONNECTION_KWARGS )
1121+ connection_kwargs ["extra" ]["session_parameters" ] = {"autocommit" : True }
1122+ with mock .patch .dict (
1123+ "os.environ" ,
1124+ AIRFLOW_CONN_SNOWFLAKE_DEFAULT = Connection (** connection_kwargs ).get_uri (),
1125+ ):
1126+ hook = SnowflakeHook ()
1127+ conn = mock_conn .return_value
1128+ cur = mock .MagicMock (rowcount = 0 )
1129+ conn .cursor .return_value = cur
1130+ type(cur ).sfqid = mock .PropertyMock (return_value = "qid" )
1131+
1132+ hook .run ("SELECT 1" , autocommit = False )
1133+
1134+ conn .autocommit .assert_not_called ()
1135+ conn .commit .assert_not_called ()
1136+
1137+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1138+ def test_run_respects_autocommit_from_hook_session_parameters (self , mock_conn ):
1139+ """AUTOCOMMIT from hook constructor session_parameters is respected."""
1140+ hook = SnowflakeHook (session_parameters = {"AUTOCOMMIT" : True })
1141+ conn = mock_conn .return_value
1142+ cur = mock .MagicMock (rowcount = 0 )
1143+ conn .cursor .return_value = cur
1144+ type(cur ).sfqid = mock .PropertyMock (return_value = "qid" )
1145+
1146+ hook .run ("SELECT 1" , autocommit = False )
1147+
1148+ conn .autocommit .assert_not_called ()
1149+ conn .commit .assert_not_called ()
1150+
1151+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1152+ def test_run_explicit_autocommit_true_overrides_session_parameter (self , mock_conn ):
1153+ """When autocommit=True is explicit, it overrides session_parameters."""
1154+ connection_kwargs = deepcopy (BASE_CONNECTION_KWARGS )
1155+ connection_kwargs ["extra" ]["session_parameters" ] = {"AUTOCOMMIT" : False }
1156+ with mock .patch .dict (
1157+ "os.environ" ,
1158+ AIRFLOW_CONN_SNOWFLAKE_DEFAULT = Connection (** connection_kwargs ).get_uri (),
1159+ ):
1160+ hook = SnowflakeHook ()
1161+ conn = mock_conn .return_value
1162+ cur = mock .MagicMock (rowcount = 0 )
1163+ conn .cursor .return_value = cur
1164+ type(cur ).sfqid = mock .PropertyMock (return_value = "qid" )
1165+
1166+ hook .run ("SELECT 1" , autocommit = True )
1167+
1168+ conn .autocommit .assert_called_once_with (True )
1169+
1170+ @mock .patch ("airflow.providers.snowflake.hooks.snowflake.SnowflakeHook.get_conn" )
1171+ def test_run_default_autocommit_without_session_parameter (self , mock_conn ):
1172+ """Without AUTOCOMMIT in session_parameters, default (False) is applied."""
1173+ hook = SnowflakeHook ()
1174+ conn = mock_conn .return_value
1175+ cur = mock .MagicMock (rowcount = 0 )
1176+ conn .cursor .return_value = cur
1177+ type(cur ).sfqid = mock .PropertyMock (return_value = "qid" )
1178+
1179+ hook .run ("SELECT 1" )
1180+
1181+ conn .autocommit .assert_called_once_with (False )
1182+
10461183 def test_get_openlineage_default_schema_with_no_schema_set (self ):
10471184 connection_kwargs = {
10481185 ** BASE_CONNECTION_KWARGS ,
0 commit comments