This is an automated email from the ASF dual-hosted git repository.

eladkal pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new ecd4d6654f Add SQLExecuteQueryOperator (#25717)
ecd4d6654f is described below

commit ecd4d6654ff8e0da4a7b8f29fd23c37c9c219076
Author: Dmytro Kazanzhy <[email protected]>
AuthorDate: Tue Oct 18 16:02:49 2022 +0300

    Add SQLExecuteQueryOperator (#25717)
    
    * Add SQLExecuteQueryOperator
    
    Co-authored-by: Dmytro Kazanzhy <[email protected]>
---
 .../providers/amazon/aws/operators/redshift_sql.py | 45 +++--------
 airflow/providers/amazon/provider.yaml             |  2 +-
 airflow/providers/apache/drill/operators/drill.py  | 37 +++------
 airflow/providers/apache/drill/provider.yaml       |  2 +-
 airflow/providers/common/sql/operators/sql.py      | 81 ++++++++++++++++++-
 airflow/providers/common/sql/provider.yaml         |  1 +
 .../databricks/operators/databricks_sql.py         | 63 +++++----------
 airflow/providers/databricks/provider.yaml         |  2 +-
 airflow/providers/exasol/operators/exasol.py       | 42 ++++------
 airflow/providers/exasol/provider.yaml             |  2 +-
 airflow/providers/jdbc/operators/jdbc.py           | 45 +++--------
 airflow/providers/jdbc/provider.yaml               |  2 +-
 .../providers/microsoft/mssql/operators/mssql.py   | 60 ++++----------
 airflow/providers/microsoft/mssql/provider.yaml    |  2 +-
 airflow/providers/mysql/operators/mysql.py         | 47 ++++-------
 airflow/providers/mysql/provider.yaml              |  2 +-
 airflow/providers/oracle/operators/oracle.py       | 34 +++-----
 airflow/providers/oracle/provider.yaml             |  2 +-
 airflow/providers/postgres/operators/postgres.py   | 63 +++++++--------
 airflow/providers/postgres/provider.yaml           |  2 +-
 airflow/providers/snowflake/operators/snowflake.py | 93 ++++++----------------
 airflow/providers/snowflake/provider.yaml          |  2 +-
 airflow/providers/sqlite/operators/sqlite.py       | 33 +++-----
 airflow/providers/sqlite/provider.yaml             |  2 +-
 airflow/providers/trino/operators/trino.py         | 54 ++++---------
 airflow/providers/trino/provider.yaml              |  2 +-
 airflow/providers/vertica/operators/vertica.py     | 30 +++----
 airflow/providers/vertica/provider.yaml            |  2 +-
 .../operators.rst                                  | 23 ++++++
 generated/provider_dependencies.json               | 26 +++---
 .../amazon/aws/operators/test_redshift_sql.py      |  8 +-
 tests/providers/common/sql/operators/test_sql.py   | 40 ++++++++++
 .../databricks/operators/test_databricks_sql.py    | 20 ++++-
 tests/providers/exasol/operators/test_exasol.py    | 41 +++++++---
 tests/providers/jdbc/operators/test_jdbc.py        | 27 ++++---
 .../microsoft/mssql/operators/test_mssql.py        | 19 +++--
 tests/providers/oracle/operators/test_oracle.py    | 13 +--
 .../snowflake/operators/test_snowflake.py          |  6 +-
 tests/providers/trino/operators/test_trino.py      | 15 ++--
 tests/providers/vertica/operators/test_vertica.py  | 14 +++-
 .../common/sql/example_sql_execute_query.py        | 62 +++++++++++++++
 41 files changed, 551 insertions(+), 517 deletions(-)

diff --git a/airflow/providers/amazon/aws/operators/redshift_sql.py 
b/airflow/providers/amazon/aws/operators/redshift_sql.py
index d5002e3748..77fd125aee 100644
--- a/airflow/providers/amazon/aws/operators/redshift_sql.py
+++ b/airflow/providers/amazon/aws/operators/redshift_sql.py
@@ -16,17 +16,14 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Iterable, Mapping, Sequence
+import warnings
+from typing import Sequence
 
-from airflow.models import BaseOperator
-from airflow.providers.amazon.aws.hooks.redshift_sql import RedshiftSQLHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 from airflow.www import utils as wwwutils
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class RedshiftSQLOperator(BaseOperator):
+class RedshiftSQLOperator(SQLExecuteQueryOperator):
     """
     Executes SQL Statements against an Amazon Redshift cluster
 
@@ -54,29 +51,11 @@ class RedshiftSQLOperator(BaseOperator):
         "sql": "postgresql" if "postgresql" in wwwutils.get_attr_renderer() 
else "sql"
     }
 
-    def __init__(
-        self,
-        *,
-        sql: str | Iterable[str],
-        redshift_conn_id: str = 'redshift_default',
-        parameters: Iterable | Mapping | None = None,
-        autocommit: bool = True,
-        **kwargs,
-    ) -> None:
-        super().__init__(**kwargs)
-        self.redshift_conn_id = redshift_conn_id
-        self.sql = sql
-        self.autocommit = autocommit
-        self.parameters = parameters
-
-    def get_hook(self) -> RedshiftSQLHook:
-        """Create and return RedshiftSQLHook.
-        :return RedshiftSQLHook: A RedshiftSQLHook instance.
-        """
-        return RedshiftSQLHook(redshift_conn_id=self.redshift_conn_id)
-
-    def execute(self, context: Context) -> None:
-        """Execute a statement against Amazon Redshift"""
-        self.log.info("Executing statement: %s", self.sql)
-        hook = self.get_hook()
-        hook.run(self.sql, autocommit=self.autocommit, 
parameters=self.parameters)
+    def __init__(self, *, redshift_conn_id: str = 'redshift_default', 
**kwargs) -> None:
+        super().__init__(conn_id=redshift_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/amazon/provider.yaml 
b/airflow/providers/amazon/provider.yaml
index eeca76e47a..ad645239a3 100644
--- a/airflow/providers/amazon/provider.yaml
+++ b/airflow/providers/amazon/provider.yaml
@@ -47,7 +47,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - boto3>=1.15.0
   # watchtower 3 has been released end Jan and introduced breaking change 
across the board that might
   # change logging behaviour:
diff --git a/airflow/providers/apache/drill/operators/drill.py 
b/airflow/providers/apache/drill/operators/drill.py
index 1aad91967b..d70f35ecfe 100644
--- a/airflow/providers/apache/drill/operators/drill.py
+++ b/airflow/providers/apache/drill/operators/drill.py
@@ -17,16 +17,13 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Iterable, Mapping, Sequence
+import warnings
+from typing import Sequence
 
-from airflow.models import BaseOperator
-from airflow.providers.apache.drill.hooks.drill import DrillHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class DrillOperator(BaseOperator):
+class DrillOperator(SQLExecuteQueryOperator):
     """
     Executes the provided SQL in the identified Drill environment.
 
@@ -47,21 +44,11 @@ class DrillOperator(BaseOperator):
     template_ext: Sequence[str] = ('.sql',)
     ui_color = '#ededed'
 
-    def __init__(
-        self,
-        *,
-        sql: str,
-        drill_conn_id: str = 'drill_default',
-        parameters: Iterable | Mapping | None = None,
-        **kwargs,
-    ) -> None:
-        super().__init__(**kwargs)
-        self.sql = sql
-        self.drill_conn_id = drill_conn_id
-        self.parameters = parameters
-        self.hook: DrillHook | None = None
-
-    def execute(self, context: Context):
-        self.log.info('Executing: %s on %s', self.sql, self.drill_conn_id)
-        self.hook = DrillHook(drill_conn_id=self.drill_conn_id)
-        self.hook.run(self.sql, parameters=self.parameters, 
split_statements=True)
+    def __init__(self, *, drill_conn_id: str = 'drill_default', **kwargs) -> 
None:
+        super().__init__(conn_id=drill_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/apache/drill/provider.yaml 
b/airflow/providers/apache/drill/provider.yaml
index 1d6c58bad9..c94df8458c 100644
--- a/airflow/providers/apache/drill/provider.yaml
+++ b/airflow/providers/apache/drill/provider.yaml
@@ -34,7 +34,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - sqlalchemy-drill>=1.1.0
 
 integrations:
diff --git a/airflow/providers/common/sql/operators/sql.py 
b/airflow/providers/common/sql/operators/sql.py
index 536b72fbff..f287fb6d86 100644
--- a/airflow/providers/common/sql/operators/sql.py
+++ b/airflow/providers/common/sql/operators/sql.py
@@ -17,8 +17,9 @@
 # under the License.
 from __future__ import annotations
 
+import ast
 import re
-from typing import TYPE_CHECKING, Any, Iterable, Mapping, Sequence, SupportsAbs
+from typing import TYPE_CHECKING, Any, Callable, Iterable, Mapping, Sequence, 
SupportsAbs
 
 from packaging.version import Version
 
@@ -26,7 +27,7 @@ from airflow.compat.functools import cached_property
 from airflow.exceptions import AirflowException
 from airflow.hooks.base import BaseHook
 from airflow.models import BaseOperator, SkipMixin
-from airflow.providers.common.sql.hooks.sql import DbApiHook, 
_backported_get_hook
+from airflow.providers.common.sql.hooks.sql import DbApiHook, 
_backported_get_hook, fetch_all_handler
 from airflow.version import version
 
 if TYPE_CHECKING:
@@ -94,7 +95,9 @@ class BaseSQLOperator(BaseOperator):
 
     The provided method is .get_db_hook(). The default behavior will try to
     retrieve the DB hook based on connection type.
-    You can custom the behavior by overriding the .get_db_hook() method.
+    You can customize the behavior by overriding the .get_db_hook() method.
+
+    :param conn_id: reference to a specific database
     """
 
     def __init__(
@@ -162,6 +165,78 @@ class BaseSQLOperator(BaseOperator):
         return self._hook
 
 
+class SQLExecuteQueryOperator(BaseSQLOperator):
+    """
+    Executes SQL code in a specific database
+    :param sql: the SQL code or string pointing to a template file to be 
executed (templated).
+    File must have a '.sql' extensions.
+    :param autocommit: (optional) if True, each command is automatically 
committed (default: False).
+    :param parameters: (optional) the parameters to render the SQL query with.
+    :param handler: (optional) the function that will be applied to the cursor 
(default: fetch_all_handler).
+    :param split_statements: (optional) if split single SQL string into 
statements (default: False).
+    :param return_last: (optional) if return the result of only last statement 
(default: True).
+
+    .. seealso::
+        For more information on how to use this operator, take a look at the 
guide:
+        :ref:`howto/operator:SQLExecuteQueryOperator`
+    """
+
+    template_fields: Sequence[str] = ('sql', 'parameters')
+    template_ext: Sequence[str] = ('.sql', '.json')
+    template_fields_renderers = {"sql": "sql", "parameters": "json"}
+    ui_color = '#cdaaed'
+
+    def __init__(
+        self,
+        *,
+        sql: str | list[str],
+        autocommit: bool = False,
+        parameters: Mapping | Iterable | None = None,
+        handler: Callable[[Any], Any] = fetch_all_handler,
+        split_statements: bool = False,
+        return_last: bool = True,
+        **kwargs,
+    ) -> None:
+        super().__init__(**kwargs)
+        self.sql = sql
+        self.autocommit = autocommit
+        self.parameters = parameters
+        self.handler = handler
+        self.split_statements = split_statements
+        self.return_last = return_last
+
+    def execute(self, context):
+        self.log.info('Executing: %s', self.sql)
+        hook = self.get_db_hook()
+        if self.do_xcom_push:
+            output = hook.run(
+                sql=self.sql,
+                autocommit=self.autocommit,
+                parameters=self.parameters,
+                handler=self.handler,
+                split_statements=self.split_statements,
+                return_last=self.return_last,
+            )
+        else:
+            output = hook.run(
+                sql=self.sql,
+                autocommit=self.autocommit,
+                parameters=self.parameters,
+                split_statements=self.split_statements,
+            )
+
+        if hasattr(self, '_process_output'):
+            for out in output:
+                self._process_output(*out)
+
+        return output
+
+    def prepare_template(self) -> None:
+        """Parse template file for attribute parameters."""
+        if isinstance(self.parameters, str):
+            self.parameters = ast.literal_eval(self.parameters)
+
+
 class SQLColumnCheckOperator(BaseSQLOperator):
     """
     Performs one or more of the templated checks in the column_checks 
dictionary.
diff --git a/airflow/providers/common/sql/provider.yaml 
b/airflow/providers/common/sql/provider.yaml
index 3086abae1b..bed15a0bd2 100644
--- a/airflow/providers/common/sql/provider.yaml
+++ b/airflow/providers/common/sql/provider.yaml
@@ -22,6 +22,7 @@ description: |
     `Common SQL Provider <https://en.wikipedia.org/wiki/SQL>`__
 
 versions:
+  - 1.3.0
   - 1.2.0
   - 1.1.0
   - 1.0.0
diff --git a/airflow/providers/databricks/operators/databricks_sql.py 
b/airflow/providers/databricks/operators/databricks_sql.py
index 3ee7d60878..c98d23d172 100644
--- a/airflow/providers/databricks/operators/databricks_sql.py
+++ b/airflow/providers/databricks/operators/databricks_sql.py
@@ -20,20 +20,20 @@ from __future__ import annotations
 
 import csv
 import json
-from typing import TYPE_CHECKING, Any, Iterable, List, Mapping, Sequence, 
Tuple, cast
+from typing import TYPE_CHECKING, Any, Sequence
 
 from databricks.sql.utils import ParamEscaper
 
 from airflow.exceptions import AirflowException
 from airflow.models import BaseOperator
-from airflow.providers.common.sql.hooks.sql import fetch_all_handler
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 from airflow.providers.databricks.hooks.databricks_sql import DatabricksSqlHook
 
 if TYPE_CHECKING:
     from airflow.utils.context import Context
 
 
-class DatabricksSqlOperator(BaseOperator):
+class DatabricksSqlOperator(SQLExecuteQueryOperator):
     """
     Executes SQL code in a Databricks SQL endpoint or a Databricks cluster
 
@@ -80,11 +80,9 @@ class DatabricksSqlOperator(BaseOperator):
     def __init__(
         self,
         *,
-        sql: str | Iterable[str],
         databricks_conn_id: str = DatabricksSqlHook.default_conn_name,
         http_path: str | None = None,
         sql_endpoint_name: str | None = None,
-        parameters: Iterable | Mapping | None = None,
         session_configuration=None,
         http_headers: list[tuple[str, str]] | None = None,
         catalog: str | None = None,
@@ -96,37 +94,31 @@ class DatabricksSqlOperator(BaseOperator):
         client_parameters: dict[str, Any] | None = None,
         **kwargs,
     ) -> None:
-        """Creates a new ``DatabricksSqlOperator``."""
-        super().__init__(**kwargs)
+        super().__init__(conn_id=databricks_conn_id, **kwargs)
         self.databricks_conn_id = databricks_conn_id
-        self.sql = sql
-        self._http_path = http_path
-        self._sql_endpoint_name = sql_endpoint_name
         self._output_path = output_path
         self._output_format = output_format
         self._csv_params = csv_params
-        self.parameters = parameters
-        self.do_xcom_push = do_xcom_push
-        self.session_config = session_configuration
-        self.http_headers = http_headers
-        self.catalog = catalog
-        self.schema = schema
-        self.client_parameters = client_parameters or {}
 
-    def _get_hook(self) -> DatabricksSqlHook:
-        return DatabricksSqlHook(
-            self.databricks_conn_id,
-            http_path=self._http_path,
-            session_configuration=self.session_config,
-            sql_endpoint_name=self._sql_endpoint_name,
-            http_headers=self.http_headers,
-            catalog=self.catalog,
-            schema=self.schema,
-            caller="DatabricksSqlOperator",
-            **self.client_parameters,
-        )
+        client_parameters = {} if client_parameters is None else 
client_parameters
+        hook_params = kwargs.pop('hook_params', {})
 
-    def _format_output(self, schema, results):
+        self.hook_params = {
+            'http_path': http_path,
+            'session_configuration': session_configuration,
+            'sql_endpoint_name': sql_endpoint_name,
+            'http_headers': http_headers,
+            'catalog': catalog,
+            'schema': schema,
+            'caller': "DatabricksSqlOperator",
+            **client_parameters,
+            **hook_params,
+        }
+
+    def get_db_hook(self) -> DatabricksSqlHook:
+        return DatabricksSqlHook(self.databricks_conn_id, **self.hook_params)
+
+    def _process_output(self, schema, results):
         if not self._output_path:
             return
         if not self._output_format:
@@ -157,17 +149,6 @@ class DatabricksSqlOperator(BaseOperator):
         else:
             raise AirflowException(f"Unsupported output format: 
'{self._output_format}'")
 
-    def execute(self, context: Context):
-        self.log.info('Executing: %s', self.sql)
-        hook = self._get_hook()
-        response = hook.run(self.sql, parameters=self.parameters, 
handler=fetch_all_handler)
-        schema, results = cast(List[Tuple[Any, Any]], response)[0]
-        # self.log.info('Schema: %s', schema)
-        # self.log.info('Results: %s', results)
-        self._format_output(schema, results)
-        if self.do_xcom_push:
-            return results
-
 
 COPY_INTO_APPROVED_FORMATS = ["CSV", "JSON", "AVRO", "ORC", "PARQUET", "TEXT", 
"BINARYFILE"]
 
diff --git a/airflow/providers/databricks/provider.yaml 
b/airflow/providers/databricks/provider.yaml
index d72f882feb..ad25de857e 100644
--- a/airflow/providers/databricks/provider.yaml
+++ b/airflow/providers/databricks/provider.yaml
@@ -41,7 +41,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - requests>=2.27,<3
   - databricks-sql-connector>=2.0.0, <3.0.0
   - aiohttp>=3.6.3, <4
diff --git a/airflow/providers/exasol/operators/exasol.py 
b/airflow/providers/exasol/operators/exasol.py
index e251413f03..6ae28a5f44 100644
--- a/airflow/providers/exasol/operators/exasol.py
+++ b/airflow/providers/exasol/operators/exasol.py
@@ -17,16 +17,13 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Iterable, Mapping, Sequence
+import warnings
+from typing import Sequence
 
-from airflow.models import BaseOperator
-from airflow.providers.exasol.hooks.exasol import ExasolHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class ExasolOperator(BaseOperator):
+class ExasolOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a specific Exasol database
 
@@ -46,23 +43,16 @@ class ExasolOperator(BaseOperator):
     ui_color = '#ededed'
 
     def __init__(
-        self,
-        *,
-        sql: str | Iterable[str],
-        exasol_conn_id: str = 'exasol_default',
-        autocommit: bool = False,
-        parameters: Iterable | Mapping | None = None,
-        schema: str | None = None,
-        **kwargs,
+        self, *, exasol_conn_id: str = 'exasol_default', schema: str | None = 
None, **kwargs
     ) -> None:
-        super().__init__(**kwargs)
-        self.exasol_conn_id = exasol_conn_id
-        self.sql = sql
-        self.autocommit = autocommit
-        self.parameters = parameters
-        self.schema = schema
-
-    def execute(self, context: Context) -> None:
-        self.log.info('Executing: %s', self.sql)
-        hook = ExasolHook(exasol_conn_id=self.exasol_conn_id, 
schema=self.schema)
-        hook.run(self.sql, autocommit=self.autocommit, 
parameters=self.parameters)
+        if schema is not None:
+            hook_params = kwargs.pop('hook_params', {})
+            kwargs['hook_params'] = {'schema': schema, **hook_params}
+
+        super().__init__(conn_id=exasol_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/exasol/provider.yaml 
b/airflow/providers/exasol/provider.yaml
index 370a9d821d..02c37aa3b8 100644
--- a/airflow/providers/exasol/provider.yaml
+++ b/airflow/providers/exasol/provider.yaml
@@ -38,7 +38,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - pyexasol>=0.5.1
   - pandas>=0.17.1
 
diff --git a/airflow/providers/jdbc/operators/jdbc.py 
b/airflow/providers/jdbc/operators/jdbc.py
index a744d8fa7b..f8f645856d 100644
--- a/airflow/providers/jdbc/operators/jdbc.py
+++ b/airflow/providers/jdbc/operators/jdbc.py
@@ -17,17 +17,13 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any, Callable, Iterable, Mapping, Sequence
+import warnings
+from typing import Sequence
 
-from airflow.models import BaseOperator
-from airflow.providers.common.sql.hooks.sql import fetch_all_handler
-from airflow.providers.jdbc.hooks.jdbc import JdbcHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class JdbcOperator(BaseOperator):
+class JdbcOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a database using jdbc driver.
 
@@ -51,28 +47,11 @@ class JdbcOperator(BaseOperator):
     template_fields_renderers = {'sql': 'sql'}
     ui_color = '#ededed'
 
-    def __init__(
-        self,
-        *,
-        sql: str | Iterable[str],
-        jdbc_conn_id: str = 'jdbc_default',
-        autocommit: bool = False,
-        parameters: Iterable | Mapping | None = None,
-        handler: Callable[[Any], Any] = fetch_all_handler,
-        **kwargs,
-    ) -> None:
-        super().__init__(**kwargs)
-        self.parameters = parameters
-        self.sql = sql
-        self.jdbc_conn_id = jdbc_conn_id
-        self.autocommit = autocommit
-        self.handler = handler
-        self.hook = None
-
-    def execute(self, context: Context):
-        self.log.info('Executing: %s', self.sql)
-        hook = JdbcHook(jdbc_conn_id=self.jdbc_conn_id)
-        if self.do_xcom_push:
-            return hook.run(self.sql, self.autocommit, 
parameters=self.parameters, handler=self.handler)
-        else:
-            return hook.run(self.sql, self.autocommit, 
parameters=self.parameters)
+    def __init__(self, *, jdbc_conn_id: str = 'jdbc_default', **kwargs) -> 
None:
+        super().__init__(conn_id=jdbc_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/jdbc/provider.yaml 
b/airflow/providers/jdbc/provider.yaml
index bb0ed61f97..30c564e100 100644
--- a/airflow/providers/jdbc/provider.yaml
+++ b/airflow/providers/jdbc/provider.yaml
@@ -37,7 +37,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - jaydebeapi>=1.1.1
 
 integrations:
diff --git a/airflow/providers/microsoft/mssql/operators/mssql.py 
b/airflow/providers/microsoft/mssql/operators/mssql.py
index b33002a9e8..df5b1a4800 100644
--- a/airflow/providers/microsoft/mssql/operators/mssql.py
+++ b/airflow/providers/microsoft/mssql/operators/mssql.py
@@ -17,19 +17,14 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Iterable, Mapping, Sequence
+import warnings
+from typing import Sequence
 
-from airflow.exceptions import AirflowException
-from airflow.models import BaseOperator
-from airflow.providers.microsoft.mssql.hooks.mssql import MsSqlHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 from airflow.www import utils as wwwutils
 
-if TYPE_CHECKING:
-    from airflow.providers.common.sql.hooks.sql import DbApiHook
-    from airflow.utils.context import Context
 
-
-class MsSqlOperator(BaseOperator):
+class MsSqlOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a specific Microsoft SQL database
 
@@ -57,42 +52,17 @@ class MsSqlOperator(BaseOperator):
     ui_color = '#ededed'
 
     def __init__(
-        self,
-        *,
-        sql: str | Iterable[str],
-        mssql_conn_id: str = 'mssql_default',
-        parameters: Iterable | Mapping | None = None,
-        autocommit: bool = False,
-        database: str | None = None,
-        **kwargs,
+        self, *, mssql_conn_id: str = 'mssql_default', database: str | None = 
None, **kwargs
     ) -> None:
-        super().__init__(**kwargs)
-        self.mssql_conn_id = mssql_conn_id
-        self.sql = sql
-        self.parameters = parameters
-        self.autocommit = autocommit
-        self.database = database
-        self._hook: MsSqlHook | DbApiHook | None = None
-
-    def get_hook(self) -> MsSqlHook | DbApiHook | None:
-        """
-        Will retrieve hook as determined by :meth:`~.Connection.get_hook` if 
one is defined, and
-        :class:`~.MsSqlHook` otherwise.
-
-        For example, if the connection ``conn_type`` is ``'odbc'``, 
:class:`~.OdbcHook` will be used.
-        """
-        if not self._hook:
-            conn = MsSqlHook.get_connection(conn_id=self.mssql_conn_id)
-            try:
-                self._hook = conn.get_hook()
-                self._hook.schema = self.database  # type: ignore[union-attr]
-            except AirflowException:
-                self._hook = MsSqlHook(mssql_conn_id=self.mssql_conn_id, 
schema=self.database)
-        return self._hook
+        if database is not None:
+            hook_params = kwargs.pop('hook_params', {})
+            kwargs['hook_params'] = {'schema': database, **hook_params}
 
-    def execute(self, context: Context) -> None:
-        self.log.info('Executing: %s', self.sql)
-        hook = self.get_hook()
-        hook.run(  # type: ignore[union-attr]
-            sql=self.sql, autocommit=self.autocommit, 
parameters=self.parameters
+        super().__init__(conn_id=mssql_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.
+            Also, you can provide `hook_params={'schema': <database>}`.""",
+            DeprecationWarning,
+            stacklevel=2,
         )
diff --git a/airflow/providers/microsoft/mssql/provider.yaml 
b/airflow/providers/microsoft/mssql/provider.yaml
index 61f7f8cd81..9d3c9a4feb 100644
--- a/airflow/providers/microsoft/mssql/provider.yaml
+++ b/airflow/providers/microsoft/mssql/provider.yaml
@@ -38,7 +38,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - pymssql>=2.1.5; platform_machine != "aarch64"
 
 integrations:
diff --git a/airflow/providers/mysql/operators/mysql.py 
b/airflow/providers/mysql/operators/mysql.py
index da919561db..0c2b482e0b 100644
--- a/airflow/providers/mysql/operators/mysql.py
+++ b/airflow/providers/mysql/operators/mysql.py
@@ -17,18 +17,14 @@
 # under the License.
 from __future__ import annotations
 
-import ast
-from typing import TYPE_CHECKING, Iterable, Mapping, Sequence
+import warnings
+from typing import Sequence
 
-from airflow.models import BaseOperator
-from airflow.providers.mysql.hooks.mysql import MySqlHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 from airflow.www import utils as wwwutils
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class MySqlOperator(BaseOperator):
+class MySqlOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a specific MySQL database
 
@@ -59,28 +55,17 @@ class MySqlOperator(BaseOperator):
     ui_color = '#ededed'
 
     def __init__(
-        self,
-        *,
-        sql: str | Iterable[str],
-        mysql_conn_id: str = 'mysql_default',
-        parameters: Iterable | Mapping | None = None,
-        autocommit: bool = False,
-        database: str | None = None,
-        **kwargs,
+        self, *, mysql_conn_id: str = 'mysql_default', database: str | None = 
None, **kwargs
     ) -> None:
-        super().__init__(**kwargs)
-        self.mysql_conn_id = mysql_conn_id
-        self.sql = sql
-        self.autocommit = autocommit
-        self.parameters = parameters
-        self.database = database
-
-    def prepare_template(self) -> None:
-        """Parse template file for attribute parameters."""
-        if isinstance(self.parameters, str):
-            self.parameters = ast.literal_eval(self.parameters)
+        if database is not None:
+            hook_params = kwargs.pop('hook_params', {})
+            kwargs['hook_params'] = {'schema': database, **hook_params}
 
-    def execute(self, context: Context) -> None:
-        self.log.info('Executing: %s', self.sql)
-        hook = MySqlHook(mysql_conn_id=self.mysql_conn_id, 
schema=self.database)
-        hook.run(self.sql, autocommit=self.autocommit, 
parameters=self.parameters)
+        super().__init__(conn_id=mysql_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.
+            Also, you can provide `hook_params={'schema': <database>}`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/mysql/provider.yaml 
b/airflow/providers/mysql/provider.yaml
index 69759d4e6d..965234657b 100644
--- a/airflow/providers/mysql/provider.yaml
+++ b/airflow/providers/mysql/provider.yaml
@@ -40,7 +40,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - mysql-connector-python>=8.0.11; platform_machine != "aarch64"
   - mysqlclient>=1.3.6; platform_machine != "aarch64"
 
diff --git a/airflow/providers/oracle/operators/oracle.py 
b/airflow/providers/oracle/operators/oracle.py
index e31f564653..a98f93b952 100644
--- a/airflow/providers/oracle/operators/oracle.py
+++ b/airflow/providers/oracle/operators/oracle.py
@@ -17,16 +17,18 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Iterable, Mapping, Sequence
+import warnings
+from typing import TYPE_CHECKING, Sequence
 
 from airflow.models import BaseOperator
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 from airflow.providers.oracle.hooks.oracle import OracleHook
 
 if TYPE_CHECKING:
     from airflow.utils.context import Context
 
 
-class OracleOperator(BaseOperator):
+class OracleOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a specific Oracle database.
 
@@ -49,26 +51,14 @@ class OracleOperator(BaseOperator):
     template_fields_renderers = {'sql': 'sql'}
     ui_color = '#ededed'
 
-    def __init__(
-        self,
-        *,
-        sql: str | Iterable[str],
-        oracle_conn_id: str = 'oracle_default',
-        parameters: Iterable | Mapping | None = None,
-        autocommit: bool = False,
-        **kwargs,
-    ) -> None:
-        super().__init__(**kwargs)
-        self.oracle_conn_id = oracle_conn_id
-        self.sql = sql
-        self.autocommit = autocommit
-        self.parameters = parameters
-
-    def execute(self, context: Context) -> None:
-        self.log.info('Executing: %s', self.sql)
-        hook = OracleHook(oracle_conn_id=self.oracle_conn_id)
-        if self.sql:
-            hook.run(self.sql, autocommit=self.autocommit, 
parameters=self.parameters)
+    def __init__(self, *, oracle_conn_id: str = 'oracle_default', **kwargs) -> 
None:
+        super().__init__(conn_id=oracle_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
 
 
 class OracleStoredProcedureOperator(BaseOperator):
diff --git a/airflow/providers/oracle/provider.yaml 
b/airflow/providers/oracle/provider.yaml
index 4acdd7c1eb..07419afcb5 100644
--- a/airflow/providers/oracle/provider.yaml
+++ b/airflow/providers/oracle/provider.yaml
@@ -40,7 +40,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - oracledb>=1.0.0
 
 integrations:
diff --git a/airflow/providers/postgres/operators/postgres.py 
b/airflow/providers/postgres/operators/postgres.py
index e12ee58d8c..1ac574da9f 100644
--- a/airflow/providers/postgres/operators/postgres.py
+++ b/airflow/providers/postgres/operators/postgres.py
@@ -17,19 +17,16 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Iterable, Mapping, Sequence
+import warnings
+from typing import Mapping, Sequence
 
 from psycopg2.sql import SQL, Identifier
 
-from airflow.models import BaseOperator
-from airflow.providers.postgres.hooks.postgres import PostgresHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 from airflow.www import utils as wwwutils
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class PostgresOperator(BaseOperator):
+class PostgresOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a specific Postgres database
 
@@ -55,42 +52,42 @@ class PostgresOperator(BaseOperator):
     def __init__(
         self,
         *,
-        sql: str | Iterable[str],
         postgres_conn_id: str = 'postgres_default',
-        autocommit: bool = False,
-        parameters: Iterable | Mapping | None = None,
         database: str | None = None,
         runtime_parameters: Mapping | None = None,
         **kwargs,
     ) -> None:
-        super().__init__(**kwargs)
-        self.sql = sql
-        self.postgres_conn_id = postgres_conn_id
-        self.autocommit = autocommit
-        self.parameters = parameters
-        self.database = database
-        self.runtime_parameters = runtime_parameters
-        self.hook: PostgresHook | None = None
+        if database is not None:
+            hook_params = kwargs.pop('hook_params', {})
+            kwargs['hook_params'] = {'schema': database, **hook_params}
+
+        if runtime_parameters:
+            sql = kwargs.pop('sql')
+            parameters = kwargs.pop('parameters', {})
 
-    def execute(self, context: Context):
-        self.hook = PostgresHook(postgres_conn_id=self.postgres_conn_id, 
schema=self.database)
-        if self.runtime_parameters:
             final_sql = []
             sql_param = {}
-            for param in self.runtime_parameters:
+            for param in runtime_parameters:
                 set_param_sql = f"SET {{}} TO %({param})s;"
                 dynamic_sql = SQL(set_param_sql).format(Identifier(f"{param}"))
                 final_sql.append(dynamic_sql)
-            for param, val in self.runtime_parameters.items():
+            for param, val in runtime_parameters.items():
                 sql_param.update({f"{param}": f"{val}"})
-            if self.parameters:
-                sql_param.update(self.parameters)
-            if isinstance(self.sql, str):
-                final_sql.append(SQL(self.sql))
+            if parameters:
+                sql_param.update(parameters)
+            if isinstance(sql, str):
+                final_sql.append(SQL(sql))
             else:
-                final_sql.extend(list(map(SQL, self.sql)))
-            self.hook.run(final_sql, self.autocommit, parameters=sql_param)
-        else:
-            self.hook.run(self.sql, self.autocommit, 
parameters=self.parameters)
-        for output in self.hook.conn.notices:
-            self.log.info(output)
+                final_sql.extend(list(map(SQL, sql)))
+
+            kwargs['sql'] = final_sql
+            kwargs['parameters'] = sql_param
+
+        super().__init__(conn_id=postgres_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.
+            Also, you can provide `hook_params={'schema': <database>}`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/postgres/provider.yaml 
b/airflow/providers/postgres/provider.yaml
index af155d7486..ebf65ab7d2 100644
--- a/airflow/providers/postgres/provider.yaml
+++ b/airflow/providers/postgres/provider.yaml
@@ -42,7 +42,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - psycopg2>=2.8.0
 
 integrations:
diff --git a/airflow/providers/snowflake/operators/snowflake.py 
b/airflow/providers/snowflake/operators/snowflake.py
index a7a7309aa3..e686e3fd6f 100644
--- a/airflow/providers/snowflake/operators/snowflake.py
+++ b/airflow/providers/snowflake/operators/snowflake.py
@@ -17,37 +17,18 @@
 # under the License.
 from __future__ import annotations
 
-from typing import Any, Callable, Iterable, Mapping, Sequence, SupportsAbs
+import warnings
+from typing import Any, Iterable, Mapping, Sequence, SupportsAbs
 
-from airflow.models import BaseOperator
-from airflow.providers.common.sql.hooks.sql import fetch_all_handler
 from airflow.providers.common.sql.operators.sql import (
     SQLCheckOperator,
+    SQLExecuteQueryOperator,
     SQLIntervalCheckOperator,
     SQLValueCheckOperator,
 )
-from airflow.providers.snowflake.hooks.snowflake import SnowflakeHook
 
 
-def get_db_hook(self) -> SnowflakeHook:
-    """
-    Create and return SnowflakeHook.
-
-    :return: a SnowflakeHook instance.
-    :rtype: SnowflakeHook
-    """
-    return SnowflakeHook(
-        snowflake_conn_id=self.snowflake_conn_id,
-        warehouse=self.warehouse,
-        database=self.database,
-        role=self.role,
-        schema=self.schema,
-        authenticator=self.authenticator,
-        session_parameters=self.session_parameters,
-    )
-
-
-class SnowflakeOperator(BaseOperator):
+class SnowflakeOperator(SQLExecuteQueryOperator):
     """
     Executes SQL code in a Snowflake database
 
@@ -80,8 +61,6 @@ class SnowflakeOperator(BaseOperator):
         through native Okta.
     :param session_parameters: You can set session-level parameters at
         the time you connect to Snowflake
-    :param handler: A Python callable that will act on cursor result.
-        By default, it will use ``fetchall``
     """
 
     template_fields: Sequence[str] = ('sql',)
@@ -92,48 +71,37 @@ class SnowflakeOperator(BaseOperator):
     def __init__(
         self,
         *,
-        sql: str | Iterable[str],
         snowflake_conn_id: str = 'snowflake_default',
-        parameters: Iterable | Mapping | None = None,
-        autocommit: bool = True,
-        do_xcom_push: bool = True,
         warehouse: str | None = None,
         database: str | None = None,
         role: str | None = None,
         schema: str | None = None,
         authenticator: str | None = None,
         session_parameters: dict | None = None,
-        handler: Callable | None = None,
         **kwargs,
     ) -> None:
-        super().__init__(**kwargs)
-        self.snowflake_conn_id = snowflake_conn_id
-        self.sql = sql
-        self.autocommit = autocommit
-        self.do_xcom_push = do_xcom_push
-        self.parameters = parameters
-        self.warehouse = warehouse
-        self.database = database
-        self.role = role
-        self.schema = schema
-        self.authenticator = authenticator
-        self.session_parameters = session_parameters
-        self.query_ids: list[str] = []
-        self.handler = handler
-
-    def get_db_hook(self) -> SnowflakeHook:
-        return get_db_hook(self)
-
-    def execute(self, context: Any):
-        """Run query on snowflake"""
-        self.log.info('Executing: %s', self.sql)
-        hook = self.get_db_hook()
-        handler = self.handler or fetch_all_handler
-        execution_info = hook.run(self.sql, self.autocommit, self.parameters, 
handler)
-        self.query_ids = hook.query_ids
-
-        if self.do_xcom_push:
-            return execution_info
+        if any([warehouse, database, role, schema, authenticator, 
session_parameters]):
+            hook_params = kwargs.pop('hook_params', {})
+            kwargs['hook_params'] = {
+                'warehouse': warehouse,
+                'database': database,
+                'role': role,
+                'schema': schema,
+                'authenticator': authenticator,
+                'session_parameters': session_parameters,
+                **hook_params,
+            }
+
+        super().__init__(conn_id=snowflake_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.
+            Also, you can provide `hook_params={'warehouse': <warehouse>, 
'database': <database>,
+            'role': <role>, 'schema': <schema>, 'authenticator': 
<authenticator>,
+            'session_parameters': <session_parameters>}`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
 
 
 class SnowflakeCheckOperator(SQLCheckOperator):
@@ -225,9 +193,6 @@ class SnowflakeCheckOperator(SQLCheckOperator):
         self.session_parameters = session_parameters
         self.query_ids: list[str] = []
 
-    def get_db_hook(self) -> SnowflakeHook:
-        return get_db_hook(self)
-
 
 class SnowflakeValueCheckOperator(SQLValueCheckOperator):
     """
@@ -294,9 +259,6 @@ class SnowflakeValueCheckOperator(SQLValueCheckOperator):
         self.session_parameters = session_parameters
         self.query_ids: list[str] = []
 
-    def get_db_hook(self) -> SnowflakeHook:
-        return get_db_hook(self)
-
 
 class SnowflakeIntervalCheckOperator(SQLIntervalCheckOperator):
     """
@@ -375,6 +337,3 @@ class 
SnowflakeIntervalCheckOperator(SQLIntervalCheckOperator):
         self.authenticator = authenticator
         self.session_parameters = session_parameters
         self.query_ids: list[str] = []
-
-    def get_db_hook(self) -> SnowflakeHook:
-        return get_db_hook(self)
diff --git a/airflow/providers/snowflake/provider.yaml 
b/airflow/providers/snowflake/provider.yaml
index 5672a03724..98f640a20e 100644
--- a/airflow/providers/snowflake/provider.yaml
+++ b/airflow/providers/snowflake/provider.yaml
@@ -46,7 +46,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - snowflake-connector-python>=2.4.1
   - snowflake-sqlalchemy>=1.1.0
 
diff --git a/airflow/providers/sqlite/operators/sqlite.py 
b/airflow/providers/sqlite/operators/sqlite.py
index c382d53ee3..6d8d1497dc 100644
--- a/airflow/providers/sqlite/operators/sqlite.py
+++ b/airflow/providers/sqlite/operators/sqlite.py
@@ -17,13 +17,13 @@
 # under the License.
 from __future__ import annotations
 
-from typing import Any, Iterable, Mapping, Sequence
+import warnings
+from typing import Sequence
 
-from airflow.models import BaseOperator
-from airflow.providers.sqlite.hooks.sqlite import SqliteHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 
 
-class SqliteOperator(BaseOperator):
+class SqliteOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a specific Sqlite database
 
@@ -44,20 +44,11 @@ class SqliteOperator(BaseOperator):
     template_fields_renderers = {'sql': 'sql'}
     ui_color = '#cdaaed'
 
-    def __init__(
-        self,
-        *,
-        sql: str | Iterable[str],
-        sqlite_conn_id: str = 'sqlite_default',
-        parameters: Iterable | Mapping | None = None,
-        **kwargs,
-    ) -> None:
-        super().__init__(**kwargs)
-        self.sqlite_conn_id = sqlite_conn_id
-        self.sql = sql
-        self.parameters = parameters or []
-
-    def execute(self, context: Mapping[Any, Any]) -> None:
-        self.log.info('Executing: %s', self.sql)
-        hook = SqliteHook(sqlite_conn_id=self.sqlite_conn_id)
-        hook.run(self.sql, parameters=self.parameters)
+    def __init__(self, *, sqlite_conn_id: str = 'sqlite_default', **kwargs) -> 
None:
+        super().__init__(conn_id=sqlite_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/sqlite/provider.yaml 
b/airflow/providers/sqlite/provider.yaml
index 18bd98582e..f07f36db55 100644
--- a/airflow/providers/sqlite/provider.yaml
+++ b/airflow/providers/sqlite/provider.yaml
@@ -37,7 +37,7 @@ versions:
   - 1.0.0
 
 dependencies:
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
 
 integrations:
   - integration-name: SQLite
diff --git a/airflow/providers/trino/operators/trino.py 
b/airflow/providers/trino/operators/trino.py
index 7ed5b5e68f..40741b048e 100644
--- a/airflow/providers/trino/operators/trino.py
+++ b/airflow/providers/trino/operators/trino.py
@@ -18,18 +18,16 @@
 """This module contains the Trino operator."""
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any, Callable, Sequence
+import warnings
+from typing import Any, Sequence
 
 from trino.exceptions import TrinoQueryError
 
-from airflow.models import BaseOperator
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 from airflow.providers.trino.hooks.trino import TrinoHook
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class TrinoOperator(BaseOperator):
+class TrinoOperator(SQLExecuteQueryOperator):
     """
     Executes sql code using a specific Trino query Engine.
 
@@ -52,43 +50,21 @@ class TrinoOperator(BaseOperator):
     template_ext: Sequence[str] = ('.sql',)
     ui_color = '#ededed'
 
-    def __init__(
-        self,
-        *,
-        sql: str | list[str],
-        trino_conn_id: str = "trino_default",
-        autocommit: bool = False,
-        parameters: tuple | None = None,
-        handler: Callable | None = None,
-        **kwargs: Any,
-    ) -> None:
-        super().__init__(**kwargs)
-        self.sql = sql
-        self.trino_conn_id = trino_conn_id
-        self.hook: TrinoHook | None = None
-        self.autocommit = autocommit
-        self.parameters = parameters
-        self.handler = handler
-
-    def get_hook(self) -> TrinoHook:
-        """Get Trino hook"""
-        return TrinoHook(
-            trino_conn_id=self.trino_conn_id,
-        )
-
-    def execute(self, context: Context) -> None:
-        """Execute Trino SQL"""
-        self.hook = self.get_hook()
-        self.hook.run(
-            sql=self.sql, autocommit=self.autocommit, 
parameters=self.parameters, handler=self.handler
+    def __init__(self, *, trino_conn_id: str = "trino_default", **kwargs: Any) 
-> None:
+        super().__init__(conn_id=trino_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
         )
 
     def on_kill(self) -> None:
-        if self.hook is not None and isinstance(self.hook, TrinoHook):
-            query_id = "'" + self.hook.query_id + "'"
+        if self._hook is not None and isinstance(self._hook, TrinoHook):
+            query_id = "'" + self._hook.query_id + "'"
             try:
-                self.log.info("Stopping query run with queryId - %s", 
self.hook.query_id)
-                self.hook.run(
+                self.log.info("Stopping query run with queryId - %s", 
self._hook.query_id)
+                self._hook.run(
                     sql=f"CALL system.runtime.kill_query(query_id => 
{query_id},message => 'Job "
                     f"killed by "
                     f"user');",
diff --git a/airflow/providers/trino/provider.yaml 
b/airflow/providers/trino/provider.yaml
index 46b1bf58d5..57da2ba254 100644
--- a/airflow/providers/trino/provider.yaml
+++ b/airflow/providers/trino/provider.yaml
@@ -39,7 +39,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - pandas>=0.17.1
   - trino>=0.301.0
 
diff --git a/airflow/providers/vertica/operators/vertica.py 
b/airflow/providers/vertica/operators/vertica.py
index 50463a7771..f9825435ed 100644
--- a/airflow/providers/vertica/operators/vertica.py
+++ b/airflow/providers/vertica/operators/vertica.py
@@ -17,16 +17,13 @@
 # under the License.
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any, Iterable, Sequence
+import warnings
+from typing import Any, Sequence
 
-from airflow.models import BaseOperator
-from airflow.providers.vertica.hooks.vertica import VerticaHook
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
 
-if TYPE_CHECKING:
-    from airflow.utils.context import Context
 
-
-class VerticaOperator(BaseOperator):
+class VerticaOperator(SQLExecuteQueryOperator):
     """
     Executes sql code in a specific Vertica database.
 
@@ -41,14 +38,11 @@ class VerticaOperator(BaseOperator):
     template_fields_renderers = {'sql': 'sql'}
     ui_color = '#b4e0ff'
 
-    def __init__(
-        self, *, sql: str | Iterable[str], vertica_conn_id: str = 
'vertica_default', **kwargs: Any
-    ) -> None:
-        super().__init__(**kwargs)
-        self.vertica_conn_id = vertica_conn_id
-        self.sql = sql
-
-    def execute(self, context: Context) -> None:
-        self.log.info('Executing: %s', self.sql)
-        hook = VerticaHook(vertica_conn_id=self.vertica_conn_id, log_sql=False)
-        hook.run(sql=self.sql)
+    def __init__(self, *, vertica_conn_id: str = 'vertica_default', **kwargs: 
Any) -> None:
+        super().__init__(conn_id=vertica_conn_id, **kwargs)
+        warnings.warn(
+            """This class is deprecated.
+            Please use 
`airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator`.""",
+            DeprecationWarning,
+            stacklevel=2,
+        )
diff --git a/airflow/providers/vertica/provider.yaml 
b/airflow/providers/vertica/provider.yaml
index d675874a0c..ccadf7b385 100644
--- a/airflow/providers/vertica/provider.yaml
+++ b/airflow/providers/vertica/provider.yaml
@@ -37,7 +37,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.2.0
-  - apache-airflow-providers-common-sql>=1.2.0
+  - apache-airflow-providers-common-sql>=1.3.0
   - vertica-python>=0.5.1
 
 integrations:
diff --git a/docs/apache-airflow-providers-common-sql/operators.rst 
b/docs/apache-airflow-providers-common-sql/operators.rst
index 402197fb52..e10759117e 100644
--- a/docs/apache-airflow-providers-common-sql/operators.rst
+++ b/docs/apache-airflow-providers-common-sql/operators.rst
@@ -21,6 +21,29 @@ SQL Operators
 These operators perform various queries against a SQL database, including
 column- and table-level data quality checks.
 
+.. _howto/operator:SQLExecuteQueryOperator:
+
+Execute SQL query
+~~~~~~~~~~~~~~~~~
+
+Use the 
:class:`~airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator` to 
run SQL query against
+different databases. Parameters of the operators are:
+
+- ``sql`` - single string, list of strings or string pointing to a template 
file to be executed;
+- ``autocommit`` (optional) if True, each command is automatically committed 
(default: False);
+- ``parameters`` (optional) the parameters to render the SQL query with.
+- ``handler`` (optional) the function that will be applied to the cursor. If 
it's ``None`` results won't returned (default: fetch_all_handler).
+- ``split_statements`` (optional) if split single SQL string into statements 
and run separately (default: False).
+- ``return_last`` (optional) depends ``split_statements`` and if it's ``True`` 
this parameter is used to return the result of only last statement or all split 
statements (default: True).
+
+The example below shows how to instantiate the SQLExecuteQueryOperator task.
+
+.. exampleinclude:: 
/../../tests/system/providers/common/sql/example_sql_execute_query.py
+    :language: python
+    :dedent: 4
+    :start-after: [START howto_operator_sql_execute_query]
+    :end-before: [END howto_operator_sql_execute_query]
+
 .. _howto/operator:SQLColumnCheckOperator:
 
 Check SQL Table Columns
diff --git a/generated/provider_dependencies.json 
b/generated/provider_dependencies.json
index 851a3de73c..b9c1e04b02 100644
--- a/generated/provider_dependencies.json
+++ b/generated/provider_dependencies.json
@@ -17,7 +17,7 @@
   },
   "amazon": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "boto3>=1.15.0",
       "jsonpath_ng>=1.5.3",
@@ -60,7 +60,7 @@
   },
   "apache.drill": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "sqlalchemy-drill>=1.1.0"
     ],
@@ -206,7 +206,7 @@
   "databricks": {
     "deps": [
       "aiohttp>=3.6.3, <4",
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "databricks-sql-connector>=2.0.0, <3.0.0",
       "requests>=2.27,<3"
@@ -270,7 +270,7 @@
   },
   "exasol": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "pandas>=0.17.1",
       "pyexasol>=0.5.1"
@@ -409,7 +409,7 @@
   },
   "jdbc": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "jaydebeapi>=1.1.1"
     ],
@@ -460,7 +460,7 @@
   },
   "microsoft.mssql": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "pymssql>=2.1.5; platform_machine != \"aarch64\""
     ],
@@ -491,7 +491,7 @@
   },
   "mysql": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "mysql-connector-python>=8.0.11; platform_machine != \"aarch64\"",
       "mysqlclient>=1.3.6; platform_machine != \"aarch64\""
@@ -536,7 +536,7 @@
   },
   "oracle": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "oracledb>=1.0.0"
     ],
@@ -568,7 +568,7 @@
   },
   "postgres": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "psycopg2>=2.8.0"
     ],
@@ -663,7 +663,7 @@
   },
   "snowflake": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "snowflake-connector-python>=2.4.1",
       "snowflake-sqlalchemy>=1.1.0"
@@ -675,7 +675,7 @@
   },
   "sqlite": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0"
+      "apache-airflow-providers-common-sql>=1.3.0"
     ],
     "cross-providers-deps": [
       "common.sql"
@@ -711,7 +711,7 @@
   },
   "trino": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "pandas>=0.17.1",
       "trino>=0.301.0"
@@ -723,7 +723,7 @@
   },
   "vertica": {
     "deps": [
-      "apache-airflow-providers-common-sql>=1.2.0",
+      "apache-airflow-providers-common-sql>=1.3.0",
       "apache-airflow>=2.2.0",
       "vertica-python>=0.5.1"
     ],
diff --git a/tests/providers/amazon/aws/operators/test_redshift_sql.py 
b/tests/providers/amazon/aws/operators/test_redshift_sql.py
index 839827a29d..9fc9aa7081 100644
--- a/tests/providers/amazon/aws/operators/test_redshift_sql.py
+++ b/tests/providers/amazon/aws/operators/test_redshift_sql.py
@@ -23,11 +23,12 @@ from unittest.mock import MagicMock
 from parameterized import parameterized
 
 from airflow.providers.amazon.aws.operators.redshift_sql import 
RedshiftSQLOperator
+from airflow.providers.common.sql.hooks.sql import fetch_all_handler
 
 
 class TestRedshiftSQLOperator(unittest.TestCase):
     @parameterized.expand([(True, ('a', 'b')), (False, ('c', 'd'))])
-    
@mock.patch("airflow.providers.amazon.aws.operators.redshift_sql.RedshiftSQLOperator.get_hook")
+    
@mock.patch("airflow.providers.amazon.aws.operators.redshift_sql.RedshiftSQLOperator.get_db_hook")
     def test_redshift_operator(self, test_autocommit, test_parameters, 
mock_get_hook):
         hook = MagicMock()
         mock_run = hook.run
@@ -38,7 +39,10 @@ class TestRedshiftSQLOperator(unittest.TestCase):
         )
         operator.execute(None)
         mock_run.assert_called_once_with(
-            sql,
+            sql=sql,
             autocommit=test_autocommit,
             parameters=test_parameters,
+            handler=fetch_all_handler,
+            return_last=True,
+            split_statements=False,
         )
diff --git a/tests/providers/common/sql/operators/test_sql.py 
b/tests/providers/common/sql/operators/test_sql.py
index 373b1b99ae..910f295d18 100644
--- a/tests/providers/common/sql/operators/test_sql.py
+++ b/tests/providers/common/sql/operators/test_sql.py
@@ -28,10 +28,12 @@ from airflow import DAG
 from airflow.exceptions import AirflowException
 from airflow.models import Connection, DagRun, TaskInstance as TI, XCom
 from airflow.operators.empty import EmptyOperator
+from airflow.providers.common.sql.hooks.sql import fetch_all_handler
 from airflow.providers.common.sql.operators.sql import (
     BranchSQLOperator,
     SQLCheckOperator,
     SQLColumnCheckOperator,
+    SQLExecuteQueryOperator,
     SQLIntervalCheckOperator,
     SQLTableCheckOperator,
     SQLThresholdCheckOperator,
@@ -56,6 +58,44 @@ def _get_mock_db_hook():
     return MockHook()
 
 
+class TestSQLExecuteQueryOperator(unittest.TestCase):
+    def _construct_operator(self, sql, **kwargs):
+        dag = DAG("test_dag", start_date=datetime.datetime(2017, 1, 1))
+        return SQLExecuteQueryOperator(
+            task_id="test_task",
+            conn_id='default_conn',
+            sql=sql,
+            **kwargs,
+            dag=dag,
+        )
+
+    @mock.patch.object(SQLExecuteQueryOperator, "get_db_hook")
+    def test_do_xcom_push(self, mock_get_db_hook):
+        operator = self._construct_operator("SELECT 1;", do_xcom_push=True)
+        operator.execute(context=MagicMock())
+
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql='SELECT 1;',
+            autocommit=False,
+            handler=fetch_all_handler,
+            parameters=None,
+            return_last=True,
+            split_statements=False,
+        )
+
+    @mock.patch.object(SQLExecuteQueryOperator, "get_db_hook")
+    def test_dont_xcom_push(self, mock_get_db_hook):
+        operator = self._construct_operator("SELECT 1;", do_xcom_push=False)
+        operator.execute(context=MagicMock())
+
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql='SELECT 1;',
+            autocommit=False,
+            parameters=None,
+            split_statements=False,
+        )
+
+
 class TestColumnCheckOperator:
 
     valid_column_mapping = {
diff --git a/tests/providers/databricks/operators/test_databricks_sql.py 
b/tests/providers/databricks/operators/test_databricks_sql.py
index 04a5b930d8..452542490e 100644
--- a/tests/providers/databricks/operators/test_databricks_sql.py
+++ b/tests/providers/databricks/operators/test_databricks_sql.py
@@ -53,7 +53,7 @@ class TestDatabricksSqlOperator(unittest.TestCase):
 
         results = op.execute(None)
 
-        assert results == mock_results
+        assert results[0][1] == mock_results
         db_mock_class.assert_called_once_with(
             DEFAULT_CONN_ID,
             http_path=None,
@@ -64,7 +64,14 @@ class TestDatabricksSqlOperator(unittest.TestCase):
             schema=None,
             caller='DatabricksSqlOperator',
         )
-        db_mock.run.assert_called_once_with(sql, parameters=None, 
handler=fetch_all_handler)
+        db_mock.run.assert_called_once_with(
+            sql=sql,
+            parameters=None,
+            handler=fetch_all_handler,
+            autocommit=False,
+            return_last=True,
+            split_statements=False,
+        )
 
     
@mock.patch('airflow.providers.databricks.operators.databricks_sql.DatabricksSqlHook')
     def test_exec_write_file(self, db_mock_class):
@@ -96,7 +103,14 @@ class TestDatabricksSqlOperator(unittest.TestCase):
             schema=None,
             caller='DatabricksSqlOperator',
         )
-        db_mock.run.assert_called_once_with(sql, parameters=None, 
handler=fetch_all_handler)
+        db_mock.run.assert_called_once_with(
+            sql=sql,
+            parameters=None,
+            handler=fetch_all_handler,
+            autocommit=False,
+            return_last=True,
+            split_statements=False,
+        )
 
 
 class TestDatabricksSqlCopyIntoOperator(unittest.TestCase):
diff --git a/tests/providers/exasol/operators/test_exasol.py 
b/tests/providers/exasol/operators/test_exasol.py
index 5f93e33a75..2150e55b3e 100644
--- a/tests/providers/exasol/operators/test_exasol.py
+++ b/tests/providers/exasol/operators/test_exasol.py
@@ -20,24 +20,43 @@ from __future__ import annotations
 import unittest
 from unittest import mock
 
+from airflow.providers.common.sql.hooks.sql import fetch_all_handler
 from airflow.providers.exasol.operators.exasol import ExasolOperator
 
 
 class TestExasol(unittest.TestCase):
-    @mock.patch('airflow.providers.exasol.hooks.exasol.ExasolHook.run')
-    def test_overwrite_autocommit(self, mock_run):
+    
@mock.patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_overwrite_autocommit(self, mock_get_db_hook):
         operator = ExasolOperator(task_id='TEST', sql='SELECT 1', 
autocommit=True)
         operator.execute({})
-        mock_run.assert_called_once_with('SELECT 1', autocommit=True, 
parameters=None)
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql='SELECT 1',
+            autocommit=True,
+            parameters=None,
+            handler=fetch_all_handler,
+            return_last=True,
+            split_statements=False,
+        )
 
-    @mock.patch('airflow.providers.exasol.hooks.exasol.ExasolHook.run')
-    def test_pass_parameters(self, mock_run):
+    
@mock.patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_pass_parameters(self, mock_get_db_hook):
         operator = ExasolOperator(task_id='TEST', sql='SELECT {value!s}', 
parameters={'value': 1})
         operator.execute({})
-        mock_run.assert_called_once_with('SELECT {value!s}', autocommit=False, 
parameters={'value': 1})
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql='SELECT {value!s}',
+            autocommit=False,
+            parameters={'value': 1},
+            handler=fetch_all_handler,
+            return_last=True,
+            split_statements=False,
+        )
 
-    @mock.patch('airflow.providers.exasol.operators.exasol.ExasolHook')
-    def test_overwrite_schema(self, mock_hook):
-        operator = ExasolOperator(task_id='TEST', sql='SELECT 1', 
schema='dummy')
-        operator.execute({})
-        mock_hook.assert_called_once_with(exasol_conn_id='exasol_default', 
schema='dummy')
+    
@mock.patch('airflow.providers.common.sql.operators.sql.BaseSQLOperator.__init__')
+    def test_overwrite_schema(self, mock_base_op):
+        ExasolOperator(task_id='TEST', sql='SELECT 1', schema='dummy')
+        mock_base_op.assert_called_once_with(
+            conn_id='exasol_default',
+            hook_params={'schema': 'dummy'},
+            default_args={},
+            task_id='TEST',
+        )
diff --git a/tests/providers/jdbc/operators/test_jdbc.py 
b/tests/providers/jdbc/operators/test_jdbc.py
index 0ba9d545fd..cdf094eec5 100644
--- a/tests/providers/jdbc/operators/test_jdbc.py
+++ b/tests/providers/jdbc/operators/test_jdbc.py
@@ -28,27 +28,28 @@ class TestJdbcOperator(unittest.TestCase):
     def setUp(self):
         self.kwargs = dict(sql='sql', task_id='test_jdbc_operator', dag=None)
 
-    @patch('airflow.providers.jdbc.operators.jdbc.JdbcHook')
-    def test_execute_do_push(self, mock_jdbc_hook):
+    
@patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_execute_do_push(self, mock_get_db_hook):
         jdbc_operator = JdbcOperator(**self.kwargs, do_xcom_push=True)
         jdbc_operator.execute(context={})
 
-        
mock_jdbc_hook.assert_called_once_with(jdbc_conn_id=jdbc_operator.jdbc_conn_id)
-        mock_jdbc_hook.return_value.run.assert_called_once_with(
-            jdbc_operator.sql,
-            jdbc_operator.autocommit,
-            parameters=jdbc_operator.parameters,
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql=jdbc_operator.sql,
+            autocommit=jdbc_operator.autocommit,
             handler=fetch_all_handler,
+            parameters=jdbc_operator.parameters,
+            return_last=True,
+            split_statements=False,
         )
 
-    @patch('airflow.providers.jdbc.operators.jdbc.JdbcHook')
-    def test_execute_dont_push(self, mock_jdbc_hook):
+    
@patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_execute_dont_push(self, mock_get_db_hook):
         jdbc_operator = JdbcOperator(**self.kwargs, do_xcom_push=False)
         jdbc_operator.execute(context={})
 
-        
mock_jdbc_hook.assert_called_once_with(jdbc_conn_id=jdbc_operator.jdbc_conn_id)
-        mock_jdbc_hook.return_value.run.assert_called_once_with(
-            jdbc_operator.sql,
-            jdbc_operator.autocommit,
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql=jdbc_operator.sql,
+            autocommit=jdbc_operator.autocommit,
             parameters=jdbc_operator.parameters,
+            split_statements=False,
         )
diff --git a/tests/providers/microsoft/mssql/operators/test_mssql.py 
b/tests/providers/microsoft/mssql/operators/test_mssql.py
index 131d5aaedb..444af0cf82 100644
--- a/tests/providers/microsoft/mssql/operators/test_mssql.py
+++ b/tests/providers/microsoft/mssql/operators/test_mssql.py
@@ -21,12 +21,13 @@ from unittest import mock
 from unittest.mock import MagicMock, Mock
 
 from airflow import AirflowException
+from airflow.providers.microsoft.mssql.hooks.mssql import MsSqlHook
 from airflow.providers.microsoft.mssql.operators.mssql import MsSqlOperator
 
 
 class TestMsSqlOperator:
-    @mock.patch('airflow.hooks.base.BaseHook.get_connection')
-    def test_get_hook_from_conn(self, get_connection):
+    
@mock.patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_get_hook_from_conn(self, mock_get_db_hook):
         """
         :class:`~.MsSqlOperator` should use the hook returned by 
:meth:`airflow.models.Connection.get_hook`
         if one is returned.
@@ -37,18 +38,20 @@ class TestMsSqlOperator:
         call of ``get_hook`` on the object returned from 
:meth:`~.BaseHook.get_connection`.
         """
         mock_hook = MagicMock()
-        get_connection.return_value.get_hook.return_value = mock_hook
+        mock_get_db_hook.return_value = mock_hook
 
         op = MsSqlOperator(task_id='test', sql='')
-        assert op.get_hook() == mock_hook
+        assert op.get_db_hook() == mock_hook
 
-    @mock.patch('airflow.hooks.base.BaseHook.get_connection')
-    def test_get_hook_default(self, get_connection):
+    @mock.patch(
+        
'airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook',
 autospec=MsSqlHook
+    )
+    def test_get_hook_default(self, mock_get_db_hook):
         """
         If :meth:`airflow.models.Connection.get_hook` does not return a hook 
(e.g. because of an invalid
         conn type), then :class:`~.MsSqlHook` should be used.
         """
-        get_connection.return_value.get_hook.side_effect = 
Mock(side_effect=AirflowException())
+        mock_get_db_hook.return_value.side_effect = 
Mock(side_effect=AirflowException())
 
         op = MsSqlOperator(task_id='test', sql='')
-        assert op.get_hook().__class__.__name__ == 'MsSqlHook'
+        assert op.get_db_hook().__class__.__name__ == 'MsSqlHook'
diff --git a/tests/providers/oracle/operators/test_oracle.py 
b/tests/providers/oracle/operators/test_oracle.py
index 1fd4a82880..21221cd01f 100644
--- a/tests/providers/oracle/operators/test_oracle.py
+++ b/tests/providers/oracle/operators/test_oracle.py
@@ -19,13 +19,14 @@ from __future__ import annotations
 import unittest
 from unittest import mock
 
+from airflow.providers.common.sql.hooks.sql import fetch_all_handler
 from airflow.providers.oracle.hooks.oracle import OracleHook
 from airflow.providers.oracle.operators.oracle import OracleOperator, 
OracleStoredProcedureOperator
 
 
 class TestOracleOperator(unittest.TestCase):
-    @mock.patch.object(OracleHook, 'run', autospec=OracleHook.run)
-    def test_execute(self, mock_run):
+    
@mock.patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_execute(self, mock_get_db_hook):
         sql = 'SELECT * FROM test_table'
         oracle_conn_id = 'oracle_default'
         parameters = {'parameter': 'value'}
@@ -41,11 +42,13 @@ class TestOracleOperator(unittest.TestCase):
             task_id=task_id,
         )
         operator.execute(context=context)
-        mock_run.assert_called_once_with(
-            mock.ANY,
-            sql,
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql=sql,
             autocommit=autocommit,
             parameters=parameters,
+            handler=fetch_all_handler,
+            return_last=True,
+            split_statements=False,
         )
 
 
diff --git a/tests/providers/snowflake/operators/test_snowflake.py 
b/tests/providers/snowflake/operators/test_snowflake.py
index d4de0feed1..d027451b86 100644
--- a/tests/providers/snowflake/operators/test_snowflake.py
+++ b/tests/providers/snowflake/operators/test_snowflake.py
@@ -35,8 +35,6 @@ DEFAULT_DATE = timezone.datetime(2015, 1, 1)
 DEFAULT_DATE_ISO = DEFAULT_DATE.isoformat()
 DEFAULT_DATE_DS = DEFAULT_DATE_ISO[:10]
 TEST_DAG_ID = 'unit_test_dag'
-LONG_MOCK_PATH = "airflow.providers.snowflake.operators.snowflake."
-LONG_MOCK_PATH += 'SnowflakeOperator.get_db_hook'
 
 
 class TestSnowflakeOperator(unittest.TestCase):
@@ -46,7 +44,7 @@ class TestSnowflakeOperator(unittest.TestCase):
         dag = DAG(TEST_DAG_ID, default_args=args)
         self.dag = dag
 
-    @mock.patch(LONG_MOCK_PATH)
+    
@mock.patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
     def test_snowflake_operator(self, mock_get_db_hook):
         sql = """
         CREATE TABLE IF NOT EXISTS test_airflow (
@@ -67,7 +65,7 @@ class TestSnowflakeOperator(unittest.TestCase):
     ],
 )
 class TestSnowflakeCheckOperators:
-    @mock.patch("airflow.providers.snowflake.operators.snowflake.get_db_hook")
+    
@mock.patch('airflow.providers.common.sql.operators.sql.BaseSQLOperator.get_db_hook')
     def test_get_db_hook(
         self,
         mock_get_db_hook,
diff --git a/tests/providers/trino/operators/test_trino.py 
b/tests/providers/trino/operators/test_trino.py
index ba32e876b6..6b10c6de1d 100644
--- a/tests/providers/trino/operators/test_trino.py
+++ b/tests/providers/trino/operators/test_trino.py
@@ -27,8 +27,8 @@ TASK_ID = "test_trino_task"
 
 
 class TestTrinoOperator(unittest.TestCase):
-    @mock.patch('airflow.providers.trino.operators.trino.TrinoHook')
-    def test_execute(self, mock_trino_hook):
+    
@mock.patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_execute(self, mock_get_db_hook):
         """Asserts that the run method is called when a TrinoOperator task is 
executed"""
 
         op = TrinoOperator(
@@ -39,6 +39,11 @@ class TestTrinoOperator(unittest.TestCase):
         )
         op.execute(None)
 
-        mock_trino_hook.assert_called_once_with(trino_conn_id=TRINO_CONN_ID)
-        mock_run = mock_trino_hook.return_value.run
-        mock_run.assert_called_once()
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql="SELECT 1;",
+            autocommit=False,
+            handler=list,
+            parameters=None,
+            return_last=True,
+            split_statements=False,
+        )
diff --git a/tests/providers/vertica/operators/test_vertica.py 
b/tests/providers/vertica/operators/test_vertica.py
index 5b2a307362..0dcb58bf9a 100644
--- a/tests/providers/vertica/operators/test_vertica.py
+++ b/tests/providers/vertica/operators/test_vertica.py
@@ -20,13 +20,21 @@ from __future__ import annotations
 import unittest
 from unittest import mock
 
+from airflow.providers.common.sql.hooks.sql import fetch_all_handler
 from airflow.providers.vertica.operators.vertica import VerticaOperator
 
 
 class TestVerticaOperator(unittest.TestCase):
-    @mock.patch('airflow.providers.vertica.operators.vertica.VerticaHook')
-    def test_execute(self, mock_hook):
+    
@mock.patch('airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator.get_db_hook')
+    def test_execute(self, mock_get_db_hook):
         sql = "select a, b, c"
         op = VerticaOperator(task_id='test_task_id', sql=sql)
         op.execute(None)
-        mock_hook.return_value.run.assert_called_once_with(sql=sql)
+        mock_get_db_hook.return_value.run.assert_called_once_with(
+            sql=sql,
+            autocommit=False,
+            handler=fetch_all_handler,
+            parameters=None,
+            return_last=True,
+            split_statements=False,
+        )
diff --git a/tests/system/providers/common/sql/example_sql_execute_query.py 
b/tests/system/providers/common/sql/example_sql_execute_query.py
new file mode 100644
index 0000000000..694ca3f2ef
--- /dev/null
+++ b/tests/system/providers/common/sql/example_sql_execute_query.py
@@ -0,0 +1,62 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from airflow import DAG
+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
+from airflow.utils.dates import datetime
+
+AIRFLOW_DB_METADATA_TABLE = "ab_role"
+connection_args = {
+    "conn_id": "airflow_db",
+    "conn_type": "Postgres",
+    "host": "postgres",
+    "schema": "postgres",
+    "login": "postgres",
+    "password": "postgres",
+    "port": 5432,
+}
+
+with DAG(
+    "example_sql_execute_query",
+    description="Example DAG for SQLExecuteQueryOperator.",
+    default_args=connection_args,
+    start_date=datetime(2021, 1, 1),
+    schedule=None,
+    catchup=False,
+) as dag:
+    """
+    ### Example SQL execute query DAG
+
+    Runs the SQLExecuteQueryOperator against the Airflow metadata DB.
+    """
+
+    # [START howto_operator_sql_execute_query]
+    execute_query = SQLExecuteQueryOperator(
+        task_id="execute_query",
+        sql=f"SELECT 1; SELECT * FROM {AIRFLOW_DB_METADATA_TABLE} LIMIT 1;",
+        split_statements=True,
+        return_last=False,
+    )
+    # [END howto_operator_sql_execute_query]
+
+
+from tests.system.utils import get_test_run  # noqa: E402
+
+# Needed to run the example DAG with pytest (see: 
tests/system/README.md#run_via_pytest)
+test_run = get_test_run(dag)

Reply via email to