feat(database): Add OceanBase support (#29496)

This commit is contained in:
yuanoOo 2024-07-09 17:26:23 +08:00 committed by GitHub
parent b481bc95b5
commit b4560d442b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 396 additions and 0 deletions

View File

@ -64,6 +64,7 @@ are compatible with Superset.
| [IBM Db2](/docs/configuration/databases#ibm-db2) | `pip install ibm_db_sa` | `db2+ibm_db://` |
| [IBM Netezza Performance Server](/docs/configuration/databases#ibm-netezza-performance-server) | `pip install nzalchemy` | `netezza+nzpy://<UserName>:<DBPassword>@<Database Host>/<Database Name>` |
| [MySQL](/docs/configuration/databases#mysql) | `pip install mysqlclient` | `mysql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` |
| [OceanBase](/docs/configuration/databases#oceanbase) | `pip install oceanbase_py` | `oceanbase://<UserName>:<DBPassword>@<Database Host>/<Database Name>` |
| [Oracle](/docs/configuration/databases#oracle) | `pip install cx_Oracle` | `oracle://` |
| [PostgreSQL](/docs/configuration/databases#postgres) | `pip install psycopg2` | `postgresql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` |
| [Presto](/docs/configuration/databases#presto) | `pip install pyhive` | `presto://` |
@ -988,6 +989,19 @@ Here's the recommended connection string:
netezza+nzpy://{username}:{password}@{hostname}:{port}/{database}
```
#### OceanBase
The [sqlalchemy-oceanbase](https://pypi.org/project/oceanbase_py/) library is the recommended
way to connect to OceanBase through SQLAlchemy.
The connection string for OceanBase looks like this:
```
oceanbase://<User>:<Password>@<Host>:<Port>/<Database>
```
#### Ocient DB
The recommended connector library for Ocient is [sqlalchemy-ocient](https://pypi.org/project/sqlalchemy-ocient).

View File

@ -122,4 +122,9 @@ export const Databases = [
href: 'https://doris.apache.org/',
imgName: 'doris.png',
},
{
title: 'OceanBase',
href: 'https://www.oceanbase.com/',
imgName: 'oceanbase.svg',
},
];

67
docs/static/img/databases/oceanbase.svg vendored Normal file
View File

@ -0,0 +1,67 @@
<!--
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.
-->
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95.26 13.73">
<defs>
<style>
.cls-1 {
fill: #0181fd;
}
.cls-2 {
fill: #fff;
}
.cls-3 {
fill: #ffa005;
}
.cls-4 {
fill: #181818;
}
.cls-5 {
fill: #07c846;
}
</style>
</defs>
<rect class="cls-2" width="95.26" height="13.73"/>
<g>
<g>
<path class="cls-4" d="M51,2.66l-4.58,8.49h2.28l.74-1.48h3.05l.24,1.48h2.28l-1.68-8.49h-2.33Zm-.7,5.34l1.44-2.83,.48,2.83h-1.92Z"/>
<path class="cls-4" d="M31.98,3.71c-.33-.41-.76-.72-1.28-.95-.52-.23-1.11-.34-1.77-.34s-1.3,.11-1.9,.34c-.6,.23-1.13,.55-1.6,.95-.47,.41-.86,.88-1.18,1.42-.32,.54-.53,1.13-.64,1.76-.11,.63-.1,1.22,.04,1.76,.13,.54,.36,1.02,.69,1.42,.33,.41,.75,.72,1.27,.95,.52,.23,1.11,.34,1.78,.34s1.29-.11,1.89-.34c.6-.23,1.13-.55,1.61-.95,.47-.41,.87-.88,1.19-1.42,.32-.54,.53-1.13,.64-1.76,.11-.63,.1-1.22-.04-1.76-.13-.54-.37-1.02-.7-1.42m-1.84,4.12c-.17,.29-.38,.53-.63,.74-.25,.21-.53,.37-.83,.49-.3,.12-.61,.17-.92,.17s-.6-.06-.86-.17c-.26-.12-.48-.28-.65-.49-.17-.21-.3-.46-.37-.74-.07-.29-.08-.6-.03-.93,.06-.34,.17-.65,.35-.93,.17-.29,.38-.53,.63-.74,.25-.21,.52-.37,.82-.49,.3-.12,.61-.17,.92-.17s.6,.06,.86,.17c.26,.12,.48,.28,.66,.49,.18,.21,.31,.46,.38,.74,.08,.29,.08,.6,.03,.93-.06,.34-.17,.65-.34,.93"/>
<polygon class="cls-4" points="46.4 9.28 42.07 9.28 42.32 7.81 46.51 7.81 46.82 5.94 42.64 5.94 42.88 4.52 47.21 4.52 47.53 2.66 41.06 2.66 39.61 11.15 46.08 11.15 46.4 9.28"/>
<polygon class="cls-4" points="61.29 7.75 58.79 2.66 56.65 2.66 55.2 11.15 57.34 11.15 58.23 6.05 60.72 11.15 62.85 11.15 64.3 2.66 62.17 2.66 61.29 7.75"/>
<path class="cls-4" d="M70.83,8.68c.04-.26,.06-.5,.04-.72-.02-.23-.08-.43-.19-.61s-.25-.33-.45-.46c-.19-.12-.44-.22-.73-.28,.34-.2,.61-.43,.8-.72,.2-.28,.33-.64,.41-1.06,.12-.71,.02-1.25-.31-1.62-.33-.38-.87-.56-1.63-.56h-3.47l-1.45,8.49h3.72c.44,0,.84-.05,1.2-.16,.37-.1,.69-.26,.97-.47,.28-.21,.51-.47,.7-.78,.19-.31,.31-.66,.38-1.06m-3.67-4.34h.67c.67,0,.96,.27,.86,.82-.09,.55-.47,.82-1.14,.82h-.67l.28-1.64Zm1.07,4.88c-.26,.14-.65,.21-1.19,.21h-.75l.31-1.8h.75c.54,0,.91,.07,1.12,.21,.21,.14,.29,.37,.23,.69-.05,.32-.21,.54-.47,.69"/>
<path class="cls-4" d="M83.57,5.97c-.16-.06-.33-.12-.5-.17-.17-.05-.32-.11-.45-.19-.13-.07-.23-.16-.3-.25-.07-.1-.09-.22-.07-.37,.04-.22,.15-.39,.35-.53,.2-.14,.43-.2,.71-.2,.22,0,.44,.05,.65,.14,.22,.09,.42,.24,.62,.43l1.14-1.72c-.37-.23-.77-.4-1.19-.51-.42-.12-.84-.17-1.25-.17-.44,0-.84,.07-1.22,.2-.38,.13-.71,.32-.99,.57-.29,.24-.52,.54-.72,.88-.19,.34-.33,.72-.4,1.14-.07,.42-.07,.77,.01,1.04,.08,.27,.21,.5,.39,.68,.18,.18,.39,.32,.63,.43,.25,.11,.5,.21,.76,.3,.22,.08,.4,.16,.56,.23,.15,.07,.27,.14,.36,.22,.09,.08,.15,.17,.17,.26,.03,.09,.03,.2,0,.33-.04,.21-.15,.4-.35,.56-.2,.17-.47,.25-.82,.25-.31,0-.6-.07-.89-.21-.29-.14-.57-.36-.84-.65l-1.22,1.78c.78,.64,1.69,.96,2.73,.96,.5,0,.96-.07,1.38-.21,.42-.14,.79-.33,1.1-.59,.32-.25,.57-.55,.78-.91,.2-.35,.34-.75,.41-1.18,.11-.65,.04-1.17-.22-1.57-.26-.4-.71-.72-1.37-.96"/>
<path class="cls-4" d="M38.16,2.42c-.57,0-1.14,.11-1.7,.33-.56,.22-1.07,.53-1.54,.92-.46,.39-.86,.86-1.19,1.41-.33,.54-.55,1.14-.66,1.8-.11,.65-.09,1.26,.05,1.81,.15,.55,.38,1.03,.71,1.43,.33,.4,.73,.71,1.21,.93,.48,.22,1.01,.33,1.57,.33,.28,0,.56-.03,.85-.08,.29-.06,.61-.14,.96-.26l.23-.08,.45-2.61c-.65,.6-1.31,.9-2,.9-.31,0-.59-.06-.84-.18-.25-.12-.45-.29-.62-.5-.16-.21-.28-.46-.34-.74-.06-.29-.07-.6,0-.93,.06-.33,.17-.64,.33-.92,.16-.29,.36-.53,.59-.74,.23-.21,.49-.37,.79-.49,.29-.12,.6-.18,.92-.18,.73,0,1.28,.31,1.67,.93l.45-2.64c-.32-.15-.64-.26-.94-.33-.3-.07-.62-.11-.95-.11"/>
<path class="cls-4" d="M78.31,9.36c-.35-.07-1.02-.11-2.18,.17l.26,1.65h2.28l-.36-1.81Z"/>
<path class="cls-4" d="M78.22,8.87l-.37-1.87c-.55,0-1.24,.09-2.1,.31-.09,.02-.19,.05-.29,.08-.47,.13-.91,.22-1.31,.28l1.25-2.46,.27,1.65c.86-.22,1.55-.3,2.1-.31l-.77-3.85h-2.33l-4.58,8.49h2.28l.82-1.62c.69-.05,1.52-.17,2.46-.43,.14-.04,.27-.07,.39-.1,1.16-.27,1.83-.24,2.18-.17"/>
<g>
<path class="cls-4" d="M89.66,6.01c-1.7,.44-2.99,.4-3.55,.35l-.3,1.83c.16,.01,.35,.02,.56,.03,.84,.02,2.06-.06,3.54-.45,1.4-.37,2.23-.34,2.65-.27l.3-1.83c-.71-.07-1.75-.03-3.21,.35"/>
<path class="cls-4" d="M90.1,2.73c-1.62,.42-2.87,.41-3.47,.36l-.45,2.8c.4,.04,1.15,.07,2.15-.07l.16-.98c.56-.07,1.19-.18,1.87-.36,1.5-.39,2.34-.34,2.73-.26l.3-1.84c-.71-.09-1.77-.05-3.29,.34"/>
<path class="cls-4" d="M89.25,9.18c-.54,.14-1.03,.23-1.48,.29l.15-.9c-.62,.07-1.16,.09-1.59,.08-.21,0-.39-.01-.55-.03l-.46,2.72c.18,.01,.39,.03,.64,.03,.84,.02,2.06-.06,3.54-.45,1.32-.35,2.13-.35,2.58-.29l.3-1.83c-.71-.06-1.72,0-3.13,.36"/>
</g>
</g>
<g>
<path class="cls-5" d="M11.91,12.89c.36-.15,.72-.29,1.1-.42,.17-.06,.35-.12,.52-.17,.14-.04,.28-.08,.42-.12,2.12-.59,4.27-.75,6.35-.52v-2.17c-2.3-.23-4.67-.03-7.02,.63-.14,.04-.28,.08-.42,.12-.18,.06-.37,.12-.55,.18-.36,.12-.72,.26-1.07,.4l.67,2.06Z"/>
<path class="cls-1" d="M20.29,2.46v6.49c-2.39-.23-4.85-.02-7.27,.69-.3,.09-.59,.18-.89,.28-.36,.12-.72,.24-1.07,.34-3.06,.9-6.16,1.22-9.18,1V4.77c2.36,.23,4.79,.02,7.18-.66,.33-.09,.65-.2,.98-.31,.33-.11,.66-.22,.98-.32,3.09-.92,6.22-1.24,9.27-1.03Z"/>
<path class="cls-3" d="M10.26,.84c-.36,.15-.72,.29-1.1,.42-.17,.06-.35,.12-.52,.17-.14,.04-.28,.08-.42,.12-2.12,.59-4.27,.75-6.35,.52v2.17c2.3,.23,4.67,.03,7.02-.63,.14-.04,.28-.08,.42-.12,.18-.06,.37-.12,.55-.18,.36-.12,.72-.26,1.07-.4l-.67-2.06Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -173,6 +173,7 @@ vertica = ["sqlalchemy-vertica-python>=0.5.9, < 0.6"]
netezza = ["nzalchemy>=11.0.2"]
starrocks = ["starrocks>=1.0.0"]
doris = ["pydoris>=1.0.0, <2.0.0"]
oceanbase = ["oceanbase_py>=0.0.1"]
development = [
"docker",
"flask-testing",

View File

@ -0,0 +1,67 @@
<!--
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.
-->
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95.26 13.73">
<defs>
<style>
.cls-1 {
fill: #0181fd;
}
.cls-2 {
fill: #fff;
}
.cls-3 {
fill: #ffa005;
}
.cls-4 {
fill: #181818;
}
.cls-5 {
fill: #07c846;
}
</style>
</defs>
<rect class="cls-2" width="95.26" height="13.73"/>
<g>
<g>
<path class="cls-4" d="M51,2.66l-4.58,8.49h2.28l.74-1.48h3.05l.24,1.48h2.28l-1.68-8.49h-2.33Zm-.7,5.34l1.44-2.83,.48,2.83h-1.92Z"/>
<path class="cls-4" d="M31.98,3.71c-.33-.41-.76-.72-1.28-.95-.52-.23-1.11-.34-1.77-.34s-1.3,.11-1.9,.34c-.6,.23-1.13,.55-1.6,.95-.47,.41-.86,.88-1.18,1.42-.32,.54-.53,1.13-.64,1.76-.11,.63-.1,1.22,.04,1.76,.13,.54,.36,1.02,.69,1.42,.33,.41,.75,.72,1.27,.95,.52,.23,1.11,.34,1.78,.34s1.29-.11,1.89-.34c.6-.23,1.13-.55,1.61-.95,.47-.41,.87-.88,1.19-1.42,.32-.54,.53-1.13,.64-1.76,.11-.63,.1-1.22-.04-1.76-.13-.54-.37-1.02-.7-1.42m-1.84,4.12c-.17,.29-.38,.53-.63,.74-.25,.21-.53,.37-.83,.49-.3,.12-.61,.17-.92,.17s-.6-.06-.86-.17c-.26-.12-.48-.28-.65-.49-.17-.21-.3-.46-.37-.74-.07-.29-.08-.6-.03-.93,.06-.34,.17-.65,.35-.93,.17-.29,.38-.53,.63-.74,.25-.21,.52-.37,.82-.49,.3-.12,.61-.17,.92-.17s.6,.06,.86,.17c.26,.12,.48,.28,.66,.49,.18,.21,.31,.46,.38,.74,.08,.29,.08,.6,.03,.93-.06,.34-.17,.65-.34,.93"/>
<polygon class="cls-4" points="46.4 9.28 42.07 9.28 42.32 7.81 46.51 7.81 46.82 5.94 42.64 5.94 42.88 4.52 47.21 4.52 47.53 2.66 41.06 2.66 39.61 11.15 46.08 11.15 46.4 9.28"/>
<polygon class="cls-4" points="61.29 7.75 58.79 2.66 56.65 2.66 55.2 11.15 57.34 11.15 58.23 6.05 60.72 11.15 62.85 11.15 64.3 2.66 62.17 2.66 61.29 7.75"/>
<path class="cls-4" d="M70.83,8.68c.04-.26,.06-.5,.04-.72-.02-.23-.08-.43-.19-.61s-.25-.33-.45-.46c-.19-.12-.44-.22-.73-.28,.34-.2,.61-.43,.8-.72,.2-.28,.33-.64,.41-1.06,.12-.71,.02-1.25-.31-1.62-.33-.38-.87-.56-1.63-.56h-3.47l-1.45,8.49h3.72c.44,0,.84-.05,1.2-.16,.37-.1,.69-.26,.97-.47,.28-.21,.51-.47,.7-.78,.19-.31,.31-.66,.38-1.06m-3.67-4.34h.67c.67,0,.96,.27,.86,.82-.09,.55-.47,.82-1.14,.82h-.67l.28-1.64Zm1.07,4.88c-.26,.14-.65,.21-1.19,.21h-.75l.31-1.8h.75c.54,0,.91,.07,1.12,.21,.21,.14,.29,.37,.23,.69-.05,.32-.21,.54-.47,.69"/>
<path class="cls-4" d="M83.57,5.97c-.16-.06-.33-.12-.5-.17-.17-.05-.32-.11-.45-.19-.13-.07-.23-.16-.3-.25-.07-.1-.09-.22-.07-.37,.04-.22,.15-.39,.35-.53,.2-.14,.43-.2,.71-.2,.22,0,.44,.05,.65,.14,.22,.09,.42,.24,.62,.43l1.14-1.72c-.37-.23-.77-.4-1.19-.51-.42-.12-.84-.17-1.25-.17-.44,0-.84,.07-1.22,.2-.38,.13-.71,.32-.99,.57-.29,.24-.52,.54-.72,.88-.19,.34-.33,.72-.4,1.14-.07,.42-.07,.77,.01,1.04,.08,.27,.21,.5,.39,.68,.18,.18,.39,.32,.63,.43,.25,.11,.5,.21,.76,.3,.22,.08,.4,.16,.56,.23,.15,.07,.27,.14,.36,.22,.09,.08,.15,.17,.17,.26,.03,.09,.03,.2,0,.33-.04,.21-.15,.4-.35,.56-.2,.17-.47,.25-.82,.25-.31,0-.6-.07-.89-.21-.29-.14-.57-.36-.84-.65l-1.22,1.78c.78,.64,1.69,.96,2.73,.96,.5,0,.96-.07,1.38-.21,.42-.14,.79-.33,1.1-.59,.32-.25,.57-.55,.78-.91,.2-.35,.34-.75,.41-1.18,.11-.65,.04-1.17-.22-1.57-.26-.4-.71-.72-1.37-.96"/>
<path class="cls-4" d="M38.16,2.42c-.57,0-1.14,.11-1.7,.33-.56,.22-1.07,.53-1.54,.92-.46,.39-.86,.86-1.19,1.41-.33,.54-.55,1.14-.66,1.8-.11,.65-.09,1.26,.05,1.81,.15,.55,.38,1.03,.71,1.43,.33,.4,.73,.71,1.21,.93,.48,.22,1.01,.33,1.57,.33,.28,0,.56-.03,.85-.08,.29-.06,.61-.14,.96-.26l.23-.08,.45-2.61c-.65,.6-1.31,.9-2,.9-.31,0-.59-.06-.84-.18-.25-.12-.45-.29-.62-.5-.16-.21-.28-.46-.34-.74-.06-.29-.07-.6,0-.93,.06-.33,.17-.64,.33-.92,.16-.29,.36-.53,.59-.74,.23-.21,.49-.37,.79-.49,.29-.12,.6-.18,.92-.18,.73,0,1.28,.31,1.67,.93l.45-2.64c-.32-.15-.64-.26-.94-.33-.3-.07-.62-.11-.95-.11"/>
<path class="cls-4" d="M78.31,9.36c-.35-.07-1.02-.11-2.18,.17l.26,1.65h2.28l-.36-1.81Z"/>
<path class="cls-4" d="M78.22,8.87l-.37-1.87c-.55,0-1.24,.09-2.1,.31-.09,.02-.19,.05-.29,.08-.47,.13-.91,.22-1.31,.28l1.25-2.46,.27,1.65c.86-.22,1.55-.3,2.1-.31l-.77-3.85h-2.33l-4.58,8.49h2.28l.82-1.62c.69-.05,1.52-.17,2.46-.43,.14-.04,.27-.07,.39-.1,1.16-.27,1.83-.24,2.18-.17"/>
<g>
<path class="cls-4" d="M89.66,6.01c-1.7,.44-2.99,.4-3.55,.35l-.3,1.83c.16,.01,.35,.02,.56,.03,.84,.02,2.06-.06,3.54-.45,1.4-.37,2.23-.34,2.65-.27l.3-1.83c-.71-.07-1.75-.03-3.21,.35"/>
<path class="cls-4" d="M90.1,2.73c-1.62,.42-2.87,.41-3.47,.36l-.45,2.8c.4,.04,1.15,.07,2.15-.07l.16-.98c.56-.07,1.19-.18,1.87-.36,1.5-.39,2.34-.34,2.73-.26l.3-1.84c-.71-.09-1.77-.05-3.29,.34"/>
<path class="cls-4" d="M89.25,9.18c-.54,.14-1.03,.23-1.48,.29l.15-.9c-.62,.07-1.16,.09-1.59,.08-.21,0-.39-.01-.55-.03l-.46,2.72c.18,.01,.39,.03,.64,.03,.84,.02,2.06-.06,3.54-.45,1.32-.35,2.13-.35,2.58-.29l.3-1.83c-.71-.06-1.72,0-3.13,.36"/>
</g>
</g>
<g>
<path class="cls-5" d="M11.91,12.89c.36-.15,.72-.29,1.1-.42,.17-.06,.35-.12,.52-.17,.14-.04,.28-.08,.42-.12,2.12-.59,4.27-.75,6.35-.52v-2.17c-2.3-.23-4.67-.03-7.02,.63-.14,.04-.28,.08-.42,.12-.18,.06-.37,.12-.55,.18-.36,.12-.72,.26-1.07,.4l.67,2.06Z"/>
<path class="cls-1" d="M20.29,2.46v6.49c-2.39-.23-4.85-.02-7.27,.69-.3,.09-.59,.18-.89,.28-.36,.12-.72,.24-1.07,.34-3.06,.9-6.16,1.22-9.18,1V4.77c2.36,.23,4.79,.02,7.18-.66,.33-.09,.65-.2,.98-.31,.33-.11,.66-.22,.98-.32,3.09-.92,6.22-1.24,9.27-1.03Z"/>
<path class="cls-3" d="M10.26,.84c-.36,.15-.72,.29-1.1,.42-.17,.06-.35,.12-.52,.17-.14,.04-.28,.08-.42,.12-2.12,.59-4.27,.75-6.35,.52v2.17c2.3,.23,4.67,.03,7.02-.63,.14-.04,.28-.08,.42-.12,.18-.06,.37-.12,.55-.18,.36-.12,.72-.26,1.07-.4l-.67-2.06Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -0,0 +1,183 @@
# 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.
import logging
import re
from re import Pattern
from typing import Any, Optional
from flask_babel import gettext as __
from sqlalchemy import Numeric, TEXT, types
from sqlalchemy.sql.type_api import TypeEngine
from superset.db_engine_specs.mysql import MySQLEngineSpec
from superset.errors import SupersetErrorType
from superset.utils.core import GenericDataType
# Regular expressions to catch custom errors
CONNECTION_ACCESS_DENIED_REGEX = re.compile(
"Access denied for user '(?P<username>.*?)'"
)
CONNECTION_INVALID_HOSTNAME_REGEX = re.compile(
"Unknown OceanBase server host '(?P<hostname>.*?)'"
)
CONNECTION_UNKNOWN_DATABASE_REGEX = re.compile("Unknown database '(?P<database>.*?)'")
CONNECTION_HOST_DOWN_REGEX = re.compile(
"Can't connect to OceanBase server on '(?P<hostname>.*?)'"
)
SYNTAX_ERROR_REGEX = re.compile(
"check the manual that corresponds to your OceanBase server "
"version for the right syntax to use near '(?P<server_error>.*)"
)
logger = logging.getLogger(__name__)
class NUMBER(Numeric):
__visit_name__ = "NUMBER"
class NUMERIC(Numeric):
__visit_name__ = "NUMERIC"
class ARRAY(TypeEngine):
__visit_name__ = "ARRAY"
@property
def python_type(self) -> Optional[type[list[Any]]]:
return list
class MAP(TypeEngine):
__visit_name__ = "MAP"
@property
def python_type(self) -> Optional[type[dict[Any, Any]]]:
return dict
class OceanBaseEngineSpec(MySQLEngineSpec):
engine = "oceanbase"
engine_aliases = {"oceanbase", "oceanbase_py"}
engine_name = "OceanBase"
max_column_name_length = 128
default_driver = "oceanbase"
sqlalchemy_uri_placeholder = (
"oceanbase://user:password@host:port/db[?key=value&key=value...]"
)
encryption_parameters = {"ssl": "0"}
supports_dynamic_schema = True
column_type_mappings = ( # type: ignore
(
re.compile(r"^tinyint", re.IGNORECASE),
types.SMALLINT(),
GenericDataType.NUMERIC,
),
(
re.compile(r"^largeint", re.IGNORECASE),
types.BIGINT(),
GenericDataType.NUMERIC,
),
(
re.compile(r"^decimal.*", re.IGNORECASE),
types.DECIMAL(),
GenericDataType.NUMERIC,
),
(
re.compile(r"^double", re.IGNORECASE),
types.FLOAT(),
GenericDataType.NUMERIC,
),
(
re.compile(r"^varchar(\((\d+)\))*$", re.IGNORECASE),
types.VARCHAR(),
GenericDataType.STRING,
),
(
re.compile(r"^char(\((\d+)\))*$", re.IGNORECASE),
types.CHAR(),
GenericDataType.STRING,
),
(
re.compile(r"^json.*", re.IGNORECASE),
types.JSON(),
GenericDataType.STRING,
),
(
re.compile(r"^binary.*", re.IGNORECASE),
types.BINARY(),
GenericDataType.STRING,
),
(
re.compile(r"^array.*", re.IGNORECASE),
ARRAY(),
GenericDataType.STRING,
),
(
re.compile(r"^map.*", re.IGNORECASE),
MAP(),
GenericDataType.STRING,
),
(
re.compile(r"^text.*", re.IGNORECASE),
TEXT(),
GenericDataType.STRING,
),
(
re.compile(r"^number.*", re.IGNORECASE),
NUMBER(),
GenericDataType.NUMERIC,
),
(
re.compile(r"^numeric.*", re.IGNORECASE),
NUMERIC(),
GenericDataType.NUMERIC,
),
)
custom_errors: dict[Pattern[str], tuple[str, SupersetErrorType, dict[str, Any]]] = {
CONNECTION_ACCESS_DENIED_REGEX: (
__('Either the username "%(username)s" or the password is incorrect.'),
SupersetErrorType.CONNECTION_ACCESS_DENIED_ERROR,
{"invalid": ["username", "password"]},
),
CONNECTION_INVALID_HOSTNAME_REGEX: (
__('Unknown OceanBase server host "%(hostname)s".'),
SupersetErrorType.CONNECTION_INVALID_HOSTNAME_ERROR,
{"invalid": ["host"]},
),
CONNECTION_HOST_DOWN_REGEX: (
__('The host "%(hostname)s" might be down and can\'t be reached.'),
SupersetErrorType.CONNECTION_HOST_DOWN_ERROR,
{"invalid": ["host", "port"]},
),
CONNECTION_UNKNOWN_DATABASE_REGEX: (
__('Unable to connect to database "%(database)s".'),
SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
{"invalid": ["database"]},
),
SYNTAX_ERROR_REGEX: (
__(
'Please check your query for syntax errors near "%(server_error)s". '
"Then, try running your query again."
),
SupersetErrorType.SYNTAX_ERROR,
{},
),
}

View File

@ -0,0 +1,59 @@
# 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 typing import Any, Optional
import pytest
from sqlalchemy import JSON, types
from superset.db_engine_specs.oceanbase import ARRAY, MAP, NUMBER, NUMERIC
from superset.utils.core import GenericDataType
from tests.unit_tests.db_engine_specs.utils import assert_column_spec
@pytest.mark.parametrize(
"native_type,sqla_type,attrs,generic_type,is_dttm",
[
# Numeric
("tinyint", types.SMALLINT, None, GenericDataType.NUMERIC, False),
("largeint", types.BIGINT, None, GenericDataType.NUMERIC, False),
("decimal(38,18)", types.DECIMAL, None, GenericDataType.NUMERIC, False),
("number(38,18)", NUMBER, None, GenericDataType.NUMERIC, False),
("numeric(38,18)", NUMERIC, None, GenericDataType.NUMERIC, False),
("double", types.FLOAT, None, GenericDataType.NUMERIC, False),
# String
("char(10)", types.CHAR, None, GenericDataType.STRING, False),
("varchar(65533)", types.VARCHAR, None, GenericDataType.STRING, False),
("binary", types.BINARY, None, GenericDataType.STRING, False),
("text", types.TEXT, None, GenericDataType.STRING, False),
# Complex type
("array<varchar(65533)>", ARRAY, None, GenericDataType.STRING, False),
("map<string,int>", MAP, None, GenericDataType.STRING, False),
("json", JSON, None, GenericDataType.STRING, False),
("jsonb", JSON, None, GenericDataType.STRING, False),
],
)
def test_get_column_spec(
native_type: str,
sqla_type: type[types.TypeEngine],
attrs: Optional[dict[str, Any]],
generic_type: GenericDataType,
is_dttm: bool,
) -> None:
from superset.db_engine_specs.oceanbase import OceanBaseEngineSpec as spec
assert_column_spec(spec, native_type, sqla_type, attrs, generic_type, is_dttm)