<h3 dir="auto">Apache Airflow version</h3>
<p dir="auto">2.3.3 (latest released)</p>
<h3 dir="auto">What happened</h3>
<p dir="auto">I trying to make custom VerticaToGoogleSheetsOperator to work with Vertica database &amp; GoogleSheets, I've installed all the required provider and successfully tested the connection. When I run VerticaToGoogleSheetsOperator I got this error message</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="Error: The connection type is not supported by VerticaToGoogleSheetsOperator. The associated hook should be a subclass of 'DbApiHook'. Got VerticaHook"><pre class="notranslate"><span class="pl-v">Error</span>: <span class="pl-v">The</span> <span class="pl-s1">connection</span> <span class="pl-s1">type</span> <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-s1">supported</span> <span class="pl-s1">by</span> <span class="pl-v">VerticaToGoogleSheetsOperator</span>. <span class="pl-v">The</span> <span class="pl-s1">associated</span> <span class="pl-s1">hook</span> <span class="pl-s1">should</span> <span class="pl-s1">be</span> <span class="pl-s1">a</span> <span class="pl-s1">subclass</span> <span class="pl-s1">of</span> <span class="pl-s">'DbApiHook'</span>. <span class="pl-v">Got</span> <span class="pl-v">VerticaHook</span></pre></div>
<h3 dir="auto">What you think should happen instead</h3>
<p dir="auto">I think it's a bug in <a href="https://github.com/apache/airflow/blob/faf3c4fe474733965ab301465f695e3cc311169c/airflow/providers/common/sql/operators/sql.py#L94">BaseSQLOperator</a> on line 94 and I know how to fix it with the <code class="notranslate">issubclass</code> check.</p>
<h3 dir="auto">How to reproduce</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import logging
import datetime
import numbers

from contextlib import closing
from typing import Any, Iterable, Mapping, Optional, Sequence, Union

from airflow.operators.sql import BaseSQLOperator
from airflow.providers.google.suite.hooks.sheets import GSheetsHook

logger = logging.getLogger(__name__)


class VerticaToGoogleSheetsOperator(BaseSQLOperator):
    &quot;&quot;&quot;
    Copy data from SQL results to provided Google Spreadsheet;
    :param sql: The SQL to execute;
    :param spreadsheet_id: The Google Sheet ID to interact with;
    :param conn_id: the connection ID used to connect to the database;
    :param parameters: The parameters to render the SQL query with;
    :param spreadsheet_range: The A1 notation of the values to retrieve;
    :param gcp_conn_id: The connection ID to use when fetching connection info;
    &quot;&quot;&quot;

    template_fields: Sequence[str] = (
        &quot;sql&quot;,
        &quot;spreadsheet_id&quot;,
        &quot;spreadsheet_range&quot;,
    )

    template_fields_renderers = {&quot;sql&quot;: &quot;sql&quot;}
    template_ext: Sequence[str] = (&quot;.sql&quot;,)

    ui_color = &quot;#a0e08c&quot;

    def __init__(
        self,
        *,
        sql: str,
        spreadsheet_id: str,
        spreadsheet_range: str,
        sql_conn_id: str = &quot;dwh&quot;,
        append_values: bool = False,
        clear_sheet: bool = True,
        gcp_conn_id: str = &quot;google_sheets&quot;,
        parameters: Optional[Union[Mapping, Iterable]] = None,
        **kwargs,
    ) -&gt; None:
        super().__init__(**kwargs)

        self.sql = sql
        self.conn_id = sql_conn_id
        self.parameters = parameters
        self.gcp_conn_id = gcp_conn_id
        self.clear_sheet = clear_sheet
        self.append_values = append_values
        self.spreadsheet_id = spreadsheet_id
        self.spreadsheet_range = spreadsheet_range

    @staticmethod
    def _data_prep(data):
        for row in data:
            item_list = []
            for item in row:
                if isinstance(item, (datetime.date, datetime.datetime)):
                    item = item.isoformat()
                elif isinstance(item, int):  # To exclude int from the number check.
                    pass
                elif isinstance(item, numbers.Number):
                    item = float(item)
                item_list.append(item)
            yield item_list

    def _get_data(self):
        hook = self.get_db_hook()
        with closing(hook.get_conn()) as conn, closing(conn.cursor()) as cur:
            self.log.info(&quot;Executing query&quot;)
            cur.execute(self.sql, self.parameters or ())

            yield [field[0] for field in cur.description]
            yield from self._data_prep(cur.fetchall())

    def execute(self, context: Any) -&gt; None:
        self.log.info(&quot;Getting data&quot;)
        values = list(self._get_data())

        self.log.info(&quot;Connecting to Google&quot;)
        sheet_hook = GSheetsHook(gcp_conn_id=self.gcp_conn_id)

        self.log.info(f&quot;Uploading data to https://docs.google.com/spreadsheets/d/{self.spreadsheet_id}&quot;)

        if self.append_values:
            sheet_hook.append_values(
                spreadsheet_id=self.spreadsheet_id,
                range_=self.spreadsheet_range,
                values=values,
            )
        else:
            if self.clear_sheet:
                sheet_hook.clear(spreadsheet_id=self.spreadsheet_id, range_=self.spreadsheet_range)
            sheet_hook.update_values(
                spreadsheet_id=self.spreadsheet_id,
                range_=self.spreadsheet_range,
                values=values,
            )"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">logging</span>
<span class="pl-k">import</span> <span class="pl-s1">datetime</span>
<span class="pl-k">import</span> <span class="pl-s1">numbers</span>

<span class="pl-k">from</span> <span class="pl-s1">contextlib</span> <span class="pl-k">import</span> <span class="pl-s1">closing</span>
<span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Any</span>, <span class="pl-v">Iterable</span>, <span class="pl-v">Mapping</span>, <span class="pl-v">Optional</span>, <span class="pl-v">Sequence</span>, <span class="pl-v">Union</span>

<span class="pl-k">from</span> <span class="pl-s1">airflow</span>.<span class="pl-s1">operators</span>.<span class="pl-s1">sql</span> <span class="pl-k">import</span> <span class="pl-v">BaseSQLOperator</span>
<span class="pl-k">from</span> <span class="pl-s1">airflow</span>.<span class="pl-s1">providers</span>.<span class="pl-s1">google</span>.<span class="pl-s1">suite</span>.<span class="pl-s1">hooks</span>.<span class="pl-s1">sheets</span> <span class="pl-k">import</span> <span class="pl-v">GSheetsHook</span>

<span class="pl-s1">logger</span> <span class="pl-c1">=</span> <span class="pl-s1">logging</span>.<span class="pl-en">getLogger</span>(<span class="pl-s1">__name__</span>)


<span class="pl-k">class</span> <span class="pl-v">VerticaToGoogleSheetsOperator</span>(<span class="pl-v">BaseSQLOperator</span>):
    <span class="pl-s">"""</span>
<span class="pl-s">    Copy data from SQL results to provided Google Spreadsheet;</span>
<span class="pl-s">    :param sql: The SQL to execute;</span>
<span class="pl-s">    :param spreadsheet_id: The Google Sheet ID to interact with;</span>
<span class="pl-s">    :param conn_id: the connection ID used to connect to the database;</span>
<span class="pl-s">    :param parameters: The parameters to render the SQL query with;</span>
<span class="pl-s">    :param spreadsheet_range: The A1 notation of the values to retrieve;</span>
<span class="pl-s">    :param gcp_conn_id: The connection ID to use when fetching connection info;</span>
<span class="pl-s">    """</span>

    <span class="pl-s1">template_fields</span>: <span class="pl-v">Sequence</span>[<span class="pl-s1">str</span>] <span class="pl-c1">=</span> (
        <span class="pl-s">"sql"</span>,
        <span class="pl-s">"spreadsheet_id"</span>,
        <span class="pl-s">"spreadsheet_range"</span>,
    )

    <span class="pl-s1">template_fields_renderers</span> <span class="pl-c1">=</span> {<span class="pl-s">"sql"</span>: <span class="pl-s">"sql"</span>}
    <span class="pl-s1">template_ext</span>: <span class="pl-v">Sequence</span>[<span class="pl-s1">str</span>] <span class="pl-c1">=</span> (<span class="pl-s">".sql"</span>,)

    <span class="pl-s1">ui_color</span> <span class="pl-c1">=</span> <span class="pl-s">"#a0e08c"</span>

    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(
        <span class="pl-s1">self</span>,
        <span class="pl-c1">*</span>,
        <span class="pl-s1">sql</span>: <span class="pl-s1">str</span>,
        <span class="pl-s1">spreadsheet_id</span>: <span class="pl-s1">str</span>,
        <span class="pl-s1">spreadsheet_range</span>: <span class="pl-s1">str</span>,
        <span class="pl-s1">sql_conn_id</span>: <span class="pl-s1">str</span> <span class="pl-c1">=</span> <span class="pl-s">"dwh"</span>,
        <span class="pl-s1">append_values</span>: <span class="pl-s1">bool</span> <span class="pl-c1">=</span> <span class="pl-c1">False</span>,
        <span class="pl-s1">clear_sheet</span>: <span class="pl-s1">bool</span> <span class="pl-c1">=</span> <span class="pl-c1">True</span>,
        <span class="pl-s1">gcp_conn_id</span>: <span class="pl-s1">str</span> <span class="pl-c1">=</span> <span class="pl-s">"google_sheets"</span>,
        <span class="pl-s1">parameters</span>: <span class="pl-v">Optional</span>[<span class="pl-v">Union</span>[<span class="pl-v">Mapping</span>, <span class="pl-v">Iterable</span>]] <span class="pl-c1">=</span> <span class="pl-c1">None</span>,
        <span class="pl-c1">**</span><span class="pl-s1">kwargs</span>,
    ) <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>:
        <span class="pl-en">super</span>().<span class="pl-en">__init__</span>(<span class="pl-c1">**</span><span class="pl-s1">kwargs</span>)

        <span class="pl-s1">self</span>.<span class="pl-s1">sql</span> <span class="pl-c1">=</span> <span class="pl-s1">sql</span>
        <span class="pl-s1">self</span>.<span class="pl-s1">conn_id</span> <span class="pl-c1">=</span> <span class="pl-s1">sql_conn_id</span>
        <span class="pl-s1">self</span>.<span class="pl-s1">parameters</span> <span class="pl-c1">=</span> <span class="pl-s1">parameters</span>
        <span class="pl-s1">self</span>.<span class="pl-s1">gcp_conn_id</span> <span class="pl-c1">=</span> <span class="pl-s1">gcp_conn_id</span>
        <span class="pl-s1">self</span>.<span class="pl-s1">clear_sheet</span> <span class="pl-c1">=</span> <span class="pl-s1">clear_sheet</span>
        <span class="pl-s1">self</span>.<span class="pl-s1">append_values</span> <span class="pl-c1">=</span> <span class="pl-s1">append_values</span>
        <span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_id</span> <span class="pl-c1">=</span> <span class="pl-s1">spreadsheet_id</span>
        <span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_range</span> <span class="pl-c1">=</span> <span class="pl-s1">spreadsheet_range</span>

    <span class="pl-en">@<span class="pl-s1">staticmethod</span></span>
    <span class="pl-k">def</span> <span class="pl-en">_data_prep</span>(<span class="pl-s1">data</span>):
        <span class="pl-k">for</span> <span class="pl-s1">row</span> <span class="pl-c1">in</span> <span class="pl-s1">data</span>:
            <span class="pl-s1">item_list</span> <span class="pl-c1">=</span> []
            <span class="pl-k">for</span> <span class="pl-s1">item</span> <span class="pl-c1">in</span> <span class="pl-s1">row</span>:
                <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">item</span>, (<span class="pl-s1">datetime</span>.<span class="pl-s1">date</span>, <span class="pl-s1">datetime</span>.<span class="pl-s1">datetime</span>)):
                    <span class="pl-s1">item</span> <span class="pl-c1">=</span> <span class="pl-s1">item</span>.<span class="pl-en">isoformat</span>()
                <span class="pl-k">elif</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">item</span>, <span class="pl-s1">int</span>):  <span class="pl-c"># To exclude int from the number check.</span>
                    <span class="pl-k">pass</span>
                <span class="pl-k">elif</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">item</span>, <span class="pl-s1">numbers</span>.<span class="pl-v">Number</span>):
                    <span class="pl-s1">item</span> <span class="pl-c1">=</span> <span class="pl-en">float</span>(<span class="pl-s1">item</span>)
                <span class="pl-s1">item_list</span>.<span class="pl-en">append</span>(<span class="pl-s1">item</span>)
            <span class="pl-k">yield</span> <span class="pl-s1">item_list</span>

    <span class="pl-k">def</span> <span class="pl-en">_get_data</span>(<span class="pl-s1">self</span>):
        <span class="pl-s1">hook</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-en">get_db_hook</span>()
        <span class="pl-k">with</span> <span class="pl-en">closing</span>(<span class="pl-s1">hook</span>.<span class="pl-en">get_conn</span>()) <span class="pl-k">as</span> <span class="pl-s1">conn</span>, <span class="pl-en">closing</span>(<span class="pl-s1">conn</span>.<span class="pl-en">cursor</span>()) <span class="pl-k">as</span> <span class="pl-s1">cur</span>:
            <span class="pl-s1">self</span>.<span class="pl-s1">log</span>.<span class="pl-en">info</span>(<span class="pl-s">"Executing query"</span>)
            <span class="pl-s1">cur</span>.<span class="pl-en">execute</span>(<span class="pl-s1">self</span>.<span class="pl-s1">sql</span>, <span class="pl-s1">self</span>.<span class="pl-s1">parameters</span> <span class="pl-c1">or</span> ())

            <span class="pl-k">yield</span> [<span class="pl-s1">field</span>[<span class="pl-c1">0</span>] <span class="pl-k">for</span> <span class="pl-s1">field</span> <span class="pl-c1">in</span> <span class="pl-s1">cur</span>.<span class="pl-s1">description</span>]
            <span class="pl-k">yield</span> <span class="pl-k">from</span> <span class="pl-s1">self</span>.<span class="pl-en">_data_prep</span>(<span class="pl-s1">cur</span>.<span class="pl-en">fetchall</span>())

    <span class="pl-k">def</span> <span class="pl-en">execute</span>(<span class="pl-s1">self</span>, <span class="pl-s1">context</span>: <span class="pl-v">Any</span>) <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>:
        <span class="pl-s1">self</span>.<span class="pl-s1">log</span>.<span class="pl-en">info</span>(<span class="pl-s">"Getting data"</span>)
        <span class="pl-s1">values</span> <span class="pl-c1">=</span> <span class="pl-en">list</span>(<span class="pl-s1">self</span>.<span class="pl-en">_get_data</span>())

        <span class="pl-s1">self</span>.<span class="pl-s1">log</span>.<span class="pl-en">info</span>(<span class="pl-s">"Connecting to Google"</span>)
        <span class="pl-s1">sheet_hook</span> <span class="pl-c1">=</span> <span class="pl-v">GSheetsHook</span>(<span class="pl-s1">gcp_conn_id</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">gcp_conn_id</span>)

        <span class="pl-s1">self</span>.<span class="pl-s1">log</span>.<span class="pl-en">info</span>(<span class="pl-s">f"Uploading data to https://docs.google.com/spreadsheets/d/<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_id</span><span class="pl-kos">}</span></span>"</span>)

        <span class="pl-k">if</span> <span class="pl-s1">self</span>.<span class="pl-s1">append_values</span>:
            <span class="pl-s1">sheet_hook</span>.<span class="pl-en">append_values</span>(
                <span class="pl-s1">spreadsheet_id</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_id</span>,
                <span class="pl-s1">range_</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_range</span>,
                <span class="pl-s1">values</span><span class="pl-c1">=</span><span class="pl-s1">values</span>,
            )
        <span class="pl-k">else</span>:
            <span class="pl-k">if</span> <span class="pl-s1">self</span>.<span class="pl-s1">clear_sheet</span>:
                <span class="pl-s1">sheet_hook</span>.<span class="pl-en">clear</span>(<span class="pl-s1">spreadsheet_id</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_id</span>, <span class="pl-s1">range_</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_range</span>)
            <span class="pl-s1">sheet_hook</span>.<span class="pl-en">update_values</span>(
                <span class="pl-s1">spreadsheet_id</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_id</span>,
                <span class="pl-s1">range_</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">spreadsheet_range</span>,
                <span class="pl-s1">values</span><span class="pl-c1">=</span><span class="pl-s1">values</span>,
            )</pre></div>
<h3 dir="auto">Operating System</h3>
<p dir="auto">Debian GNU/Linux 11 (bullseye)</p>
<h3 dir="auto">Versions of Apache Airflow Providers</h3>
<p dir="auto">apache-airflow-providers-amazon==4.0.0<br>
apache-airflow-providers-celery==3.0.0<br>
apache-airflow-providers-cncf-kubernetes==4.1.0<br>
apache-airflow-providers-common-sql==1.0.0<br>
apache-airflow-providers-docker==3.0.0<br>
apache-airflow-providers-elasticsearch==4.0.0<br>
apache-airflow-providers-ftp==3.0.0<br>
apache-airflow-providers-google==8.1.0<br>
apache-airflow-providers-grpc==3.0.0<br>
apache-airflow-providers-hashicorp==3.0.0<br>
apache-airflow-providers-http==3.0.0<br>
apache-airflow-providers-imap==3.0.0<br>
apache-airflow-providers-microsoft-azure==4.0.0<br>
apache-airflow-providers-microsoft-mssql==3.1.0<br>
apache-airflow-providers-mysql==3.0.0<br>
apache-airflow-providers-odbc==3.0.0<br>
apache-airflow-providers-postgres==5.0.0<br>
apache-airflow-providers-redis==3.0.0<br>
apache-airflow-providers-sendgrid==3.0.0<br>
apache-airflow-providers-sftp==3.0.0<br>
apache-airflow-providers-slack==5.0.0<br>
apache-airflow-providers-sqlite==3.0.0<br>
apache-airflow-providers-ssh==3.0.0<br>
apache-airflow-providers-telegram==3.0.0<br>
apache-airflow-providers-vertica==3.1.0</p>
<h3 dir="auto">Deployment</h3>
<p dir="auto">Official Apache Airflow Helm Chart</p>
<h3 dir="auto">Deployment details</h3>
<p dir="auto">terraform, helm, k8s, cloud</p>
<h3 dir="auto">Anything else</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Are you willing to submit PR?</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Yes I am willing to submit a PR!</li>
</ul>
<h3 dir="auto">Code of Conduct</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I agree to follow this project's <a href="https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md">Code of Conduct</a></li>
</ul>
<h3 dir="auto">Apache Airflow version</h3>
<p dir="auto">2.3.3 (latest released)</p>
<h3 dir="auto">What happened</h3>
<p dir="auto">I trying to make SqlSensor to work with Oracle database, I've installed all the required provider and successfully tested the connection. When I run SqlSensor I got this error message<br>
<code class="notranslate">ERROR - Failed to execute job 32 for task check_exec_date (The connection type is not supported by SqlSensor. The associated hook should be a subclass of </code>DbApiHook<code class="notranslate">. Got OracleHook; 419)</code></p>
<h3 dir="auto">What you think should happen instead</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">How to reproduce</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Operating System</h3>
<p dir="auto">Ubuntu 20.04.4 LTS</p>
<h3 dir="auto">Versions of Apache Airflow Providers</h3>
<p dir="auto">apache-airflow-providers-common-sql==1.0.0<br>
apache-airflow-providers-ftp==3.0.0<br>
apache-airflow-providers-http==3.0.0<br>
apache-airflow-providers-imap==3.0.0<br>
apache-airflow-providers-oracle==3.2.0<br>
apache-airflow-providers-postgres==5.1.0<br>
apache-airflow-providers-sqlite==3.0.0</p>
<h3 dir="auto">Deployment</h3>
<p dir="auto">Other</p>
<h3 dir="auto">Deployment details</h3>
<p dir="auto">Run on Windows Subsystem for Linux</p>
<h3 dir="auto">Anything else</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Are you willing to submit PR?</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Yes I am willing to submit a PR!</li>
</ul>
<h3 dir="auto">Code of Conduct</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I agree to follow this project's <a href="https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md">Code of Conduct</a></li>
</ul>