[Features]Add dbt doris adapter (#9299)
* Add dbt doris adapter * Add licence header to each file * Fix licence header
This commit is contained in:
@ -33,6 +33,7 @@ header:
|
||||
- '**/*.patch'
|
||||
- '**/*.log'
|
||||
- '**/*.sql'
|
||||
- '**/*.lock'
|
||||
- 'tsan_suppressions'
|
||||
- 'docs/.markdownlintignore'
|
||||
- 'fe/fe-core/src/test/resources/data/net_snmp_normal'
|
||||
|
||||
139
extension/dbt-doris/.gitignore
vendored
Normal file
139
extension/dbt-doris/.gitignore
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
201
extension/dbt-doris/LICENSE
Normal file
201
extension/dbt-doris/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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.
|
||||
43
extension/dbt-doris/Makefile
Normal file
43
extension/dbt-doris/Makefile
Normal file
@ -0,0 +1,43 @@
|
||||
# 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.
|
||||
|
||||
checkfiles = dbt/adapters test/
|
||||
py_warn = PYTHONDEVMODE=1
|
||||
|
||||
up:
|
||||
@poetry update
|
||||
|
||||
deps:
|
||||
@poetry install
|
||||
|
||||
style: deps
|
||||
@isort -src $(checkfiles)
|
||||
@black $(checkfiles)
|
||||
|
||||
check: deps
|
||||
@black --check $(checkfiles) || (echo "Please run 'make style' to auto-fix style issues" && false)
|
||||
@pflake8 $(checkfiles)
|
||||
@bandit -x tests -r $(checkfiles)
|
||||
@mypy $(checkfiles)
|
||||
|
||||
test: deps
|
||||
$(py_warn) pytest
|
||||
|
||||
build:
|
||||
@poetry build
|
||||
|
||||
ci: check test
|
||||
26
extension/dbt-doris/README.md
Normal file
26
extension/dbt-doris/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# dbt-doris
|
||||
|
||||
This is the doris adapter plugin for dbt.
|
||||
|
||||
## Install
|
||||
|
||||
```shell
|
||||
git clone https://github.com/apache/incubator-doris.git
|
||||
cd incubator-doris/extension/dbt-doris && pip install .
|
||||
```
|
||||
|
||||
## Configuring your profile
|
||||
|
||||
Example entry for profiles.yml:
|
||||
|
||||
```yaml
|
||||
your_profile_name:
|
||||
target: dev
|
||||
outputs:
|
||||
dev:
|
||||
type: doris
|
||||
host: 127.0.0.1
|
||||
port: 9030
|
||||
username: root
|
||||
schema: dbt
|
||||
```
|
||||
30
extension/dbt-doris/dbt/adapters/doris/__init__.py
Normal file
30
extension/dbt-doris/dbt/adapters/doris/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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 dbt.adapters.base import AdapterPlugin
|
||||
from dbt.adapters.doris.connections import DorisAdapterCredentials
|
||||
from dbt.adapters.doris.impl import DorisAdapter
|
||||
from dbt.include import doris
|
||||
|
||||
Plugin = AdapterPlugin(
|
||||
adapter=DorisAdapter,
|
||||
credentials=DorisAdapterCredentials,
|
||||
include_path=doris.PACKAGE_PATH,
|
||||
)
|
||||
33
extension/dbt-doris/dbt/adapters/doris/column.py
Normal file
33
extension/dbt-doris/dbt/adapters/doris/column.py
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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 dataclasses import dataclass
|
||||
|
||||
from dbt.adapters.base.column import Column
|
||||
|
||||
|
||||
@dataclass
|
||||
class DorisColumn(Column):
|
||||
@property
|
||||
def quoted(self) -> str:
|
||||
return "`{}`".format(self.column)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<DorisColumn {self.name} ({self.data_type})>"
|
||||
125
extension/dbt-doris/dbt/adapters/doris/connections.py
Normal file
125
extension/dbt-doris/dbt/adapters/doris/connections.py
Normal file
@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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 contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
from typing import ContextManager, Optional, Union
|
||||
|
||||
import MySQLdb
|
||||
import MySQLdb.cursors
|
||||
from dbt import exceptions
|
||||
from dbt.adapters.base import Credentials
|
||||
from dbt.adapters.sql import SQLConnectionManager
|
||||
from dbt.contracts.connection import AdapterResponse, Connection, ConnectionState
|
||||
from dbt.events import AdapterLogger
|
||||
|
||||
logger = AdapterLogger("doris")
|
||||
|
||||
|
||||
@dataclass
|
||||
class DorisAdapterCredentials(Credentials):
|
||||
host: str = "127.0.0.1"
|
||||
port: int = 9030
|
||||
username: str = "root"
|
||||
password: str = ""
|
||||
database: Optional[str] = None
|
||||
schema: Optional[str] = None
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "doris"
|
||||
|
||||
def _connection_keys(self):
|
||||
return "host", "port", "user", "schema"
|
||||
|
||||
@property
|
||||
def unique_field(self) -> str:
|
||||
return self.host
|
||||
|
||||
def __post_init__(self):
|
||||
if self.database is not None and self.database != self.schema:
|
||||
raise exceptions.RuntimeException(
|
||||
f" schema: {self.schema} \n"
|
||||
f" database: {self.database} \n"
|
||||
f"On Doris, database must be omitted or have the same value as"
|
||||
f" schema."
|
||||
)
|
||||
|
||||
|
||||
class DorisAdapterConnectionManager(SQLConnectionManager):
|
||||
TYPE = "doris"
|
||||
|
||||
@classmethod
|
||||
def open(cls, connection: Connection) -> Connection:
|
||||
if connection.state == "open":
|
||||
logger.debug("Connection is already open, skipping open")
|
||||
return connection
|
||||
credentials = connection.credentials
|
||||
kwargs = {
|
||||
"host": credentials.host,
|
||||
"port": credentials.port,
|
||||
"user": credentials.username,
|
||||
"password": credentials.password,
|
||||
}
|
||||
try:
|
||||
connection.handle = MySQLdb.connect(**kwargs)
|
||||
connection.state = ConnectionState.OPEN
|
||||
except MySQLdb.Error as e:
|
||||
logger.debug(f"Error connecting to database: {e}")
|
||||
connection.handle = None
|
||||
connection.state = ConnectionState.FAIL
|
||||
raise exceptions.FailedToConnectException(str(e))
|
||||
return connection
|
||||
|
||||
def cancel(self, connection: Connection):
|
||||
connection.handle.close()
|
||||
|
||||
@classmethod
|
||||
def get_response(cls, cursor: MySQLdb.cursors.Cursor) -> Union[AdapterResponse, str]:
|
||||
code = "Unknown cursor state/status"
|
||||
rows = cursor.rowcount
|
||||
return AdapterResponse(
|
||||
code=code,
|
||||
_message=f"{rows} rows affected",
|
||||
rows_affected=rows,
|
||||
)
|
||||
|
||||
@contextmanager # type: ignore
|
||||
def exception_handler(self, sql: str) -> ContextManager: # type: ignore
|
||||
try:
|
||||
yield
|
||||
except MySQLdb.DatabaseError as e:
|
||||
logger.debug(f"Doris database error: {e}, sql: {sql}")
|
||||
raise exceptions.DatabaseException(str(e)) from e
|
||||
except Exception as e:
|
||||
logger.debug(f"Error running SQL: {sql}")
|
||||
if isinstance(e, exceptions.RuntimeException):
|
||||
raise e
|
||||
raise exceptions.RuntimeException(str(e)) from e
|
||||
|
||||
def begin(self):
|
||||
"""
|
||||
https://doris.apache.org/zh-CN/sql-reference/sql-statements/Data%20Manipulation/BEGIN.html#description
|
||||
Doris only support transaction in insert, just ignore it
|
||||
"""
|
||||
pass
|
||||
|
||||
def commit(self):
|
||||
pass
|
||||
172
extension/dbt-doris/dbt/adapters/doris/impl.py
Normal file
172
extension/dbt-doris/dbt/adapters/doris/impl.py
Normal file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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 concurrent.futures import Future
|
||||
from enum import Enum
|
||||
from typing import Callable, Dict, List, Optional, Set, Tuple
|
||||
|
||||
import agate
|
||||
import dbt.exceptions
|
||||
from dbt.adapters.base.impl import _expect_row_value, catch_as_completed
|
||||
from dbt.adapters.base.relation import InformationSchema
|
||||
from dbt.adapters.doris.column import DorisColumn
|
||||
from dbt.adapters.doris.connections import DorisAdapterConnectionManager
|
||||
from dbt.adapters.doris.relation import DorisRelation
|
||||
from dbt.adapters.protocol import AdapterConfig
|
||||
from dbt.adapters.sql import SQLAdapter
|
||||
from dbt.adapters.sql.impl import LIST_RELATIONS_MACRO_NAME, LIST_SCHEMAS_MACRO_NAME
|
||||
from dbt.clients.agate_helper import table_from_rows
|
||||
from dbt.contracts.graph.manifest import Manifest
|
||||
from dbt.contracts.relation import RelationType
|
||||
from dbt.utils import executor
|
||||
|
||||
|
||||
class Engine(str, Enum):
|
||||
olap = "olap"
|
||||
mysql = "mysql"
|
||||
elasticsearch = "elasticsearch"
|
||||
hive = "hive"
|
||||
iceberg = "iceberg"
|
||||
|
||||
|
||||
class DorisConfig(AdapterConfig):
|
||||
engine: Engine = Engine.olap
|
||||
duplicate_key: Tuple[str]
|
||||
partition_by: Tuple[str]
|
||||
partition_by_init: List[str]
|
||||
distributed_by: Tuple[str]
|
||||
buckets: int
|
||||
properties: Dict[str, str]
|
||||
|
||||
|
||||
class DorisAdapter(SQLAdapter):
|
||||
ConnectionManager = DorisAdapterConnectionManager
|
||||
Relation = DorisRelation
|
||||
AdapterSpecificConfigs = DorisConfig
|
||||
Column = DorisColumn
|
||||
|
||||
@classmethod
|
||||
def date_function(cls) -> str:
|
||||
return "current_date()"
|
||||
|
||||
@classmethod
|
||||
def convert_datetime_type(cls, agate_table: agate.Table, col_idx: int) -> str:
|
||||
return "datetime"
|
||||
|
||||
@classmethod
|
||||
def convert_text_type(cls, agate_table: agate.Table, col_idx: int) -> str:
|
||||
return "string"
|
||||
|
||||
def quote(self, identifier):
|
||||
return "`{}`".format(identifier)
|
||||
|
||||
def check_schema_exists(self, database, schema):
|
||||
results = self.execute_macro(LIST_SCHEMAS_MACRO_NAME, kwargs={"database": database})
|
||||
|
||||
exists = True if schema in [row[0] for row in results] else False
|
||||
return exists
|
||||
|
||||
def get_relation(self, database: Optional[str], schema: str, identifier: str):
|
||||
if not self.Relation.include_policy.database:
|
||||
database = None
|
||||
|
||||
return super().get_relation(database, schema, identifier)
|
||||
|
||||
def list_relations_without_caching(self, schema_relation: DorisRelation) -> List[DorisRelation]:
|
||||
kwargs = {"schema_relation": schema_relation}
|
||||
results = self.execute_macro(LIST_RELATIONS_MACRO_NAME, kwargs=kwargs)
|
||||
|
||||
relations = []
|
||||
for row in results:
|
||||
if len(row) != 4:
|
||||
raise dbt.exceptions.RuntimeException(
|
||||
f"Invalid value from 'show table extended ...', "
|
||||
f"got {len(row)} values, expected 4"
|
||||
)
|
||||
_database, name, schema, type_info = row
|
||||
rel_type = RelationType.View if "view" in type_info else RelationType.Table
|
||||
relation = self.Relation.create(
|
||||
database=None,
|
||||
schema=schema,
|
||||
identifier=name,
|
||||
type=rel_type,
|
||||
)
|
||||
relations.append(relation)
|
||||
|
||||
return relations
|
||||
|
||||
def get_catalog(self, manifest):
|
||||
schema_map = self._get_catalog_schemas(manifest)
|
||||
if len(schema_map) > 1:
|
||||
dbt.exceptions.raise_compiler_error(
|
||||
f"Expected only one database in get_catalog, found " f"{list(schema_map)}"
|
||||
)
|
||||
|
||||
with executor(self.config) as tpe:
|
||||
futures: List[Future[agate.Table]] = []
|
||||
for info, schemas in schema_map.items():
|
||||
for schema in schemas:
|
||||
futures.append(
|
||||
tpe.submit_connected(
|
||||
self,
|
||||
schema,
|
||||
self._get_one_catalog,
|
||||
info,
|
||||
[schema],
|
||||
manifest,
|
||||
)
|
||||
)
|
||||
catalogs, exceptions = catch_as_completed(futures)
|
||||
return catalogs, exceptions
|
||||
|
||||
@classmethod
|
||||
def _catalog_filter_schemas(cls, manifest: Manifest) -> Callable[[agate.Row], bool]:
|
||||
schemas = frozenset((None, s.lower()) for d, s in manifest.get_used_schemas())
|
||||
|
||||
def _(row: agate.Row) -> bool:
|
||||
table_database = _expect_row_value("table_database", row)
|
||||
table_schema = _expect_row_value("table_schema", row)
|
||||
if table_schema is None:
|
||||
return False
|
||||
return (table_database, table_schema.lower()) in schemas
|
||||
|
||||
return _
|
||||
|
||||
@classmethod
|
||||
def _catalog_filter_table(cls, table: agate.Table, manifest: Manifest) -> agate.Table:
|
||||
table = table_from_rows(
|
||||
table.rows,
|
||||
table.column_names,
|
||||
text_only_columns=["table_schema", "table_name"],
|
||||
)
|
||||
return table.where(cls._catalog_filter_schemas(manifest))
|
||||
|
||||
def _get_one_catalog(
|
||||
self,
|
||||
information_schema: InformationSchema,
|
||||
schemas: Set[str],
|
||||
manifest: Manifest,
|
||||
) -> agate.Table:
|
||||
if len(schemas) != 1:
|
||||
dbt.exceptions.raise_compiler_error(
|
||||
f"Expected only one schema in Doris _get_one_catalog, found " f"{schemas}"
|
||||
)
|
||||
|
||||
return super()._get_one_catalog(information_schema, schemas, manifest)
|
||||
56
extension/dbt-doris/dbt/adapters/doris/relation.py
Normal file
56
extension/dbt-doris/dbt/adapters/doris/relation.py
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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 dataclasses import dataclass
|
||||
|
||||
from dbt.adapters.base.relation import BaseRelation, Policy
|
||||
from dbt.exceptions import RuntimeException
|
||||
|
||||
|
||||
@dataclass
|
||||
class DorisQuotePolicy(Policy):
|
||||
database: bool = False
|
||||
schema: bool = True
|
||||
identifier: bool = True
|
||||
|
||||
|
||||
@dataclass
|
||||
class DorisIncludePolicy(Policy):
|
||||
database: bool = False
|
||||
schema: bool = True
|
||||
identifier: bool = True
|
||||
|
||||
|
||||
@dataclass(frozen=True, eq=False, repr=False)
|
||||
class DorisRelation(BaseRelation):
|
||||
quote_policy: DorisQuotePolicy = DorisQuotePolicy()
|
||||
include_policy: DorisIncludePolicy = DorisIncludePolicy()
|
||||
quote_character: str = "`"
|
||||
|
||||
def __post_init__(self):
|
||||
if self.database != self.schema and self.database:
|
||||
raise RuntimeException(f"Cannot set database {self.database} in Doris!")
|
||||
|
||||
def render(self):
|
||||
if self.include_policy.database and self.include_policy.schema:
|
||||
raise RuntimeException(
|
||||
"Got a Doris relation with schema and database set to include, but only one can be set"
|
||||
)
|
||||
return super().render()
|
||||
23
extension/dbt-doris/dbt/include/doris/__init__.py
Normal file
23
extension/dbt-doris/dbt/include/doris/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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 os
|
||||
|
||||
PACKAGE_PATH = os.path.dirname(__file__)
|
||||
25
extension/dbt-doris/dbt/include/doris/dbt_project.yml
Normal file
25
extension/dbt-doris/dbt/include/doris/dbt_project.yml
Normal file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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.
|
||||
|
||||
name: dbt_doris
|
||||
version: 1.0
|
||||
config-version: 2
|
||||
|
||||
macro-paths: ["macros"]
|
||||
@ -0,0 +1,31 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__get_columns_in_relation(relation) -%}
|
||||
{% call statement('get_columns_in_relation', fetch_result=True) %}
|
||||
select column_name as `column`,
|
||||
data_type as 'dtype',
|
||||
character_maximum_length as char_size,
|
||||
numeric_precision,
|
||||
numeric_scale
|
||||
from information_schema.columns
|
||||
where table_schema = '{{ relation.schema }}'
|
||||
and table_name = '{{ relation.identifier }}'
|
||||
{% endcall %}
|
||||
{% set table = load_result('get_columns_in_relation').table %}
|
||||
{{ return(sql_convert_columns_in_relation(table)) }}
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,20 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__current_timestamp() -%}
|
||||
current_timestamp()
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,93 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__list_relations_without_caching(schema_relation) -%}
|
||||
{% call statement('list_relations_without_caching', fetch_result=True) %}
|
||||
select
|
||||
null as "database",
|
||||
table_name as name,
|
||||
table_schema as "schema",
|
||||
case when table_type = 'BASE TABLE' then 'table'
|
||||
when table_type = 'VIEW' then 'view'
|
||||
else table_type end as table_type
|
||||
from information_schema.tables
|
||||
where table_schema = '{{ schema_relation.schema }}'
|
||||
{% endcall %}
|
||||
{{ return(load_result('list_relations_without_caching').table) }}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__get_catalog(information_schema, schemas) -%}
|
||||
{%- call statement('catalog', fetch_result=True) -%}
|
||||
with tables as (
|
||||
select
|
||||
null as "table_database",
|
||||
table_schema,
|
||||
table_name,
|
||||
case when table_type = 'BASE TABLE' then 'table'
|
||||
when table_type = 'VIEW' then 'view'
|
||||
else table_type
|
||||
end as table_type,
|
||||
null as table_owner
|
||||
from {{ information_schema }}.tables
|
||||
),
|
||||
columns as (
|
||||
select
|
||||
null as "table_database",
|
||||
table_schema as "table_schema",
|
||||
table_name as "table_name",
|
||||
null as "table_comment",
|
||||
column_name as "column_name",
|
||||
ordinal_position as "column_index",
|
||||
data_type as "column_type",
|
||||
null as "column_comment"
|
||||
from {{ information_schema }}.columns
|
||||
)
|
||||
select
|
||||
columns.table_database,
|
||||
columns.table_schema,
|
||||
columns.table_name,
|
||||
tables.table_type,
|
||||
columns.table_comment,
|
||||
tables.table_owner,
|
||||
columns.column_name,
|
||||
columns.column_index,
|
||||
columns.column_type,
|
||||
columns.column_comment
|
||||
from tables
|
||||
join columns using (table_schema, table_name)
|
||||
where tables.table_schema not in ('information_schema', '__statistics__')
|
||||
and (
|
||||
{%- for schema in schemas -%}
|
||||
upper(tables.table_schema) = upper('{{ schema }}'){%- if not loop.last %} or {% endif -%}
|
||||
{%- endfor -%}
|
||||
)
|
||||
order by column_index
|
||||
{%- endcall -%}
|
||||
|
||||
{{ return(load_result('catalog').table) }}
|
||||
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__check_schema_exists(database, schema) -%}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__list_schemas(database) -%}
|
||||
{% call statement('list_schemas', fetch_result=True, auto_begin=False) -%}
|
||||
select distinct schema_name from information_schema.schemata
|
||||
{%- endcall %}
|
||||
{{ return(load_result('list_schemas').table) }}
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,110 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__engine() -%}
|
||||
{% set label = 'ENGINE' %}
|
||||
{% set engine = config.get('engine', validator=validation.any[basestring]) %}
|
||||
{% if engine is not none %}
|
||||
{{ label }} = {{ engine }}
|
||||
{% else %}
|
||||
{{ label }} = OLAP
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__partition_by() -%}
|
||||
{% set cols = config.get('partition_by') %}
|
||||
{% if cols is not none %}
|
||||
PARTITION BY RANGE (
|
||||
{% for col in cols %}
|
||||
{{ col }}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
)(
|
||||
{% set init = config.get('partition_by_init',validator=validation.any[list]) %}
|
||||
{% if init is not none %}
|
||||
{% for row in init %}
|
||||
{{ row }}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
)
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__duplicate_key() -%}
|
||||
{% set cols = config.get('duplicate_key', validator=validation.any[list]) %}
|
||||
{% if cols is not none %}
|
||||
DUPLICATE KEY (
|
||||
{% for item in cols %}
|
||||
{{ item }}
|
||||
{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
)
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__distributed_by(column_names) -%}
|
||||
{% set label = 'DISTRIBUTED BY HASH' %}
|
||||
{% set engine = config.get('engine', validator=validation.any[basestring]) %}
|
||||
{% set cols = config.get('distributed_by', validator=validation.any[list]) %}
|
||||
{% if cols is none and engine in [none,'OLAP'] %}
|
||||
{% set cols = column_names %}
|
||||
{% endif %}
|
||||
{% if cols %}
|
||||
{{ label }} (
|
||||
{% for item in cols %}
|
||||
{{ item }}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
) BUCKETS {{ config.get('buckets', validator=validation.any[int]) or 1 }}
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__properties() -%}
|
||||
{% set properties = config.get('properties', validator=validation.any[dict]) or {"replication_num":"1"} %}
|
||||
{% if properties is not none %}
|
||||
PROPERTIES (
|
||||
{% for key, value in properties.items() %}
|
||||
"{{ key }}" = "{{ value }}"{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
)
|
||||
{% endif %}
|
||||
{%- endmacro%}
|
||||
|
||||
{% macro doris__drop_relation(relation) -%}
|
||||
{% call statement('drop_relation', auto_begin=False) %}
|
||||
drop {{ relation.type }} if exists {{ relation }}
|
||||
{% endcall %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__truncate_relation(relation) -%}
|
||||
{% call statement('truncate_relation') %}
|
||||
truncate table {{ relation }}
|
||||
{% endcall %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro doris__rename_relation(from_relation, to_relation) -%}
|
||||
{% call statement('drop_relation') %}
|
||||
drop {{ to_relation.type }} if exists {{ to_relation }}
|
||||
{% endcall %}
|
||||
{% call statement('rename_relation') %}
|
||||
{% if to_relation.is_view %}
|
||||
{% set results = run_query('show create view ' + from_relation.render() ) %}
|
||||
create view {{ to_relation }} as {{ results[0]['Create View'].replace(from_relation.table, to_relation.table).split('AS',1)[1] }}
|
||||
drop view if exists {{ from_relation }};
|
||||
{% else %}
|
||||
alter table {{ from_relation }} rename {{ to_relation.table }}
|
||||
{% endif %}
|
||||
{% endcall %}
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,22 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__drop_schema(relation) -%}
|
||||
{% call statement('drop_schema') %}
|
||||
drop schema if exists {{ relation.without_identifier() }}
|
||||
{% endcall %}
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,20 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__generate_database_name(custom_database_name=none, node=none) -%}
|
||||
{% do return(None) %}
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,28 @@
|
||||
-- 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.
|
||||
|
||||
{% macro is_incremental() %}
|
||||
{% if not execute %}
|
||||
{{ return(False) }}
|
||||
{% else %}
|
||||
{% set relation = adapter.get_relation(this.database, this.schema, this.table) %}
|
||||
{{ return(relation is not none
|
||||
and relation.type == 'table'
|
||||
and model.config.materialized in ['incremental','partition']
|
||||
and not should_full_refresh()) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@ -0,0 +1,65 @@
|
||||
-- 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.
|
||||
|
||||
{% macro get_distinct_partitions(relation, partition_by) %}
|
||||
{% set sql %}
|
||||
select distinct {{ ','.join(partition_by) }} from {{ relation }} order by {{ ','.join(partition_by) }}
|
||||
{% endset %}
|
||||
{{ return(run_query(sql)) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro get_partition_items(partition, quote) %}
|
||||
{% set items = [] %}
|
||||
{% for item in partition %}
|
||||
{% if quote %}
|
||||
{{ items.append('"{}"'.format(item+1)) }}
|
||||
{% else %}
|
||||
{{ items.append('{}'.format(item)) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ return(items) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro insert_data_to_tmp_partitions(tmp_relation, target_relation, partitions) %}
|
||||
{% for partition in partitions %}
|
||||
{% set items = get_partition_items(partition) %}
|
||||
{% set p = ''.join(items) %}
|
||||
{% call statement() %}
|
||||
insert into {{ target_relation }} temporary partition (tp{{ p }}) select * from {{ tmp_relation }} where
|
||||
{% for k,v in partition.items() %}
|
||||
{{ k }} = {{ v }}
|
||||
{% endfor %}
|
||||
{% endcall %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro create_partitions(relation, partitions) %}
|
||||
{% for partition in partitions %}
|
||||
{% set items = get_partition_items(partition) %}
|
||||
{% set items_quote = get_partition_items(partition, True) %}
|
||||
{% set p = ''.join(items) %}
|
||||
{% call statement() %}
|
||||
alter table {{ relation }} drop temporary partition if exists tp{{ p }}
|
||||
{% endcall %}
|
||||
{% call statement() %}
|
||||
alter table {{ relation }} add temporary partition tp{{ p }} values less than ({{ ','.join(items_quote) }})
|
||||
{% endcall %}
|
||||
{% call statement() %}
|
||||
alter table {{ relation }} add partition if not exists p{{ p }} values less than ({{ ','.join(items_quote) }})
|
||||
{% endcall %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
@ -0,0 +1,109 @@
|
||||
-- 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.
|
||||
|
||||
{% materialization partition, default -%}
|
||||
|
||||
{% set partition_by = config.get('partition_by') %}
|
||||
|
||||
{% set target_relation = this.incorporate(type='table') %}
|
||||
{% set existing_relation = load_relation(this) %}
|
||||
{% set tmp_relation = make_temp_relation(target_relation) %}
|
||||
{%- set full_refresh_mode = (should_full_refresh()) -%}
|
||||
|
||||
{% set on_schema_change = incremental_validate_on_schema_change(config.get('on_schema_change'), default='ignore') %}
|
||||
|
||||
{% set tmp_identifier = model['name'] + '__dbt_tmp' %}
|
||||
{% set backup_identifier = model['name'] + "__dbt_backup" %}
|
||||
|
||||
-- the intermediate_ and backup_ relations should not already exist in the database; get_relation
|
||||
-- will return None in that case. Otherwise, we get a relation that we can drop
|
||||
-- later, before we try to use this name for the current operation. This has to happen before
|
||||
-- BEGIN, in a separate transaction
|
||||
{% set preexisting_intermediate_relation = adapter.get_relation(identifier=tmp_identifier,
|
||||
schema=schema,
|
||||
database=database) %}
|
||||
{% set preexisting_backup_relation = adapter.get_relation(identifier=backup_identifier,
|
||||
schema=schema,
|
||||
database=database) %}
|
||||
{{ drop_relation_if_exists(preexisting_intermediate_relation) }}
|
||||
{{ drop_relation_if_exists(preexisting_backup_relation) }}
|
||||
|
||||
{{ run_hooks(pre_hooks, inside_transaction=False) }}
|
||||
|
||||
-- `BEGIN` happens here:
|
||||
{{ run_hooks(pre_hooks, inside_transaction=True) }}
|
||||
|
||||
{% set to_drop = [] %}
|
||||
|
||||
{# -- first check whether we want to full refresh for source view or config reasons #}
|
||||
{% set trigger_full_refresh = (full_refresh_mode or existing_relation.is_view) %}
|
||||
|
||||
{% if existing_relation is none %}
|
||||
{% set build_sql = create_table_as(False, target_relation, sql) %}
|
||||
{% elif trigger_full_refresh %}
|
||||
{#-- Make sure the backup doesn't exist so we don't encounter issues with the rename below #}
|
||||
{% set tmp_identifier = model['name'] + '__dbt_tmp' %}
|
||||
{% set backup_identifier = model['name'] + '__dbt_backup' %}
|
||||
{% set intermediate_relation = existing_relation.incorporate(path={"identifier": tmp_identifier}) %}
|
||||
{% set backup_relation = existing_relation.incorporate(path={"identifier": backup_identifier}) %}
|
||||
|
||||
{% set build_sql = create_table_as(False, intermediate_relation, sql) %}
|
||||
{% set need_swap = true %}
|
||||
{% do to_drop.append(backup_relation) %}
|
||||
{% else %}
|
||||
{% do to_drop.append(tmp_relation) %}
|
||||
{% do run_query(create_table_as(True, tmp_relation, sql)) %}
|
||||
{% do adapter.expand_target_column_types(
|
||||
from_relation=tmp_relation,
|
||||
to_relation=target_relation) %}
|
||||
|
||||
{% set distinct_partitions = get_distinct_partitions(tmp_relation, partition_by) %}
|
||||
{% do create_partitions(target_relation,distinct_partitions) %}
|
||||
{% do insert_data_to_tmp_partitions(tmp_relation,target_relation, distinct_partitions) %}
|
||||
{% set build_sql = get_partition_replace_sql(target_relation, distinct_partitions) %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% call statement("main") %}
|
||||
{{ build_sql }}
|
||||
{% endcall %}
|
||||
|
||||
{% if need_swap %}
|
||||
{% do adapter.rename_relation(target_relation, backup_relation) %}
|
||||
{% do adapter.rename_relation(intermediate_relation, target_relation) %}
|
||||
{% endif %}
|
||||
|
||||
{% do persist_docs(target_relation, model) %}
|
||||
|
||||
{% if existing_relation is none or existing_relation.is_view or should_full_refresh() %}
|
||||
{% do create_indexes(target_relation) %}
|
||||
{% endif %}
|
||||
|
||||
{{ run_hooks(post_hooks, inside_transaction=True) }}
|
||||
|
||||
-- `COMMIT` happens here
|
||||
{% do adapter.commit() %}
|
||||
|
||||
{% for rel in to_drop %}
|
||||
{% do adapter.drop_relation(rel) %}
|
||||
{% endfor %}
|
||||
|
||||
{{ run_hooks(post_hooks, inside_transaction=False) }}
|
||||
|
||||
{{ return({'relations': [target_relation]}) }}
|
||||
|
||||
{%- endmaterialization %}
|
||||
@ -0,0 +1,26 @@
|
||||
-- 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.
|
||||
|
||||
{% macro get_partition_replace_sql(relation, partitions) %}
|
||||
{% for partition in partitions %}
|
||||
{% set items = get_partition_items(partition) %}
|
||||
{% set p = ''.join(items) %}
|
||||
alter table {{ relation }} replace partition (p{{ p }}) with temporary partition (tp{{ p }}) properties (
|
||||
"strict_range" = "false"
|
||||
);
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
@ -0,0 +1,45 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__create_csv_table(model, agate_table) -%}
|
||||
{% set column_override = model['config'].get('column_types', {}) %}
|
||||
{% set quote_seed_column = model['config'].get('quote_columns', None) %}
|
||||
|
||||
{% set sql %}
|
||||
create table {{ this.render() }}
|
||||
(
|
||||
{% for col_name in agate_table.column_names %}
|
||||
{% set inferred_type = adapter.convert_type(agate_table, loop.index0) %}
|
||||
{% set type = column_override.get(col_name, inferred_type) %}
|
||||
{% set column_name = (col_name | string) %}
|
||||
{{ adapter.quote_seed_column(column_name, quote_seed_column) }} {{ type }}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
)
|
||||
{{ doris__engine() }}
|
||||
{{ doris__duplicate_key() }}
|
||||
{{ doris__partition_by() }}
|
||||
{{ doris__distributed_by(agate_table.column_names) }}
|
||||
{{ doris__properties() }}
|
||||
{% endset %}
|
||||
|
||||
{% call statement('_') %}
|
||||
{{ sql }}
|
||||
{% endcall %}
|
||||
|
||||
{{ return(sql) }}
|
||||
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,154 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__snapshot_string_as_time(timestamp) -%}
|
||||
{%- set result = "str_to_date('" ~ timestamp ~ "', '%Y-%m-%d %T')" -%}
|
||||
{{ return(result) }}
|
||||
{%- endmacro %}
|
||||
|
||||
{% materialization snapshot, adapter='doris' %}
|
||||
{%- set config = model['config'] -%}
|
||||
|
||||
{%- set target_table = model.get('alias', model.get('name')) -%}
|
||||
|
||||
{%- set strategy_name = config.get('strategy') -%}
|
||||
{%- set unique_key = config.get('unique_key') %}
|
||||
|
||||
{% if not adapter.check_schema_exists(model.database, model.schema) %}
|
||||
{% do create_schema(model.database, model.schema) %}
|
||||
{% endif %}
|
||||
|
||||
{% set target_relation_exists, target_relation = get_or_create_relation(
|
||||
database=none,
|
||||
schema=model.schema,
|
||||
identifier=target_table,
|
||||
type='table') -%}
|
||||
|
||||
{%- if not target_relation.is_table -%}
|
||||
{% do exceptions.relation_wrong_type(target_relation, 'table') %}
|
||||
{%- endif -%}
|
||||
|
||||
{{ run_hooks(pre_hooks, inside_transaction=False) }}
|
||||
|
||||
{{ run_hooks(pre_hooks, inside_transaction=True) }}
|
||||
|
||||
{% set strategy_macro = strategy_dispatch(strategy_name) %}
|
||||
{% set strategy = strategy_macro(model, "snapshotted_data", "source_data", config, target_relation_exists) %}
|
||||
|
||||
{% if not target_relation_exists %}
|
||||
|
||||
{% set build_sql = build_snapshot_table(strategy, model['compiled_sql']) %}
|
||||
{% set final_sql = create_table_as(False, target_relation, build_sql) %}
|
||||
|
||||
{% call statement('main') %}
|
||||
{{ final_sql }}
|
||||
{% endcall %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{{ adapter.valid_snapshot_target(target_relation) }}
|
||||
|
||||
{% set staging_table = build_snapshot_staging_table(strategy, sql, target_relation) %}
|
||||
|
||||
-- this may no-op if the database does not require column expansion
|
||||
{% do adapter.expand_target_column_types(from_relation=staging_table,
|
||||
to_relation=target_relation) %}
|
||||
|
||||
{% set missing_columns = adapter.get_missing_columns(staging_table, target_relation)
|
||||
| rejectattr('name', 'equalto', 'dbt_change_type')
|
||||
| rejectattr('name', 'equalto', 'DBT_CHANGE_TYPE')
|
||||
| rejectattr('name', 'equalto', 'dbt_unique_key')
|
||||
| rejectattr('name', 'equalto', 'DBT_UNIQUE_KEY')
|
||||
| list %}
|
||||
|
||||
{% do create_columns(target_relation, missing_columns) %}
|
||||
|
||||
{% set source_columns = adapter.get_columns_in_relation(staging_table)
|
||||
| rejectattr('name', 'equalto', 'dbt_change_type')
|
||||
| rejectattr('name', 'equalto', 'DBT_CHANGE_TYPE')
|
||||
| rejectattr('name', 'equalto', 'dbt_unique_key')
|
||||
| rejectattr('name', 'equalto', 'DBT_UNIQUE_KEY')
|
||||
| list %}
|
||||
|
||||
{% set quoted_source_columns = [] %}
|
||||
{% for column in source_columns %}
|
||||
{% do quoted_source_columns.append(adapter.quote(column.name)) %}
|
||||
{% endfor %}
|
||||
|
||||
{% set final_sql_update = doris__snapshot_merge_sql_update(
|
||||
target = target_relation,
|
||||
source = staging_table,
|
||||
insert_cols = quoted_source_columns
|
||||
)
|
||||
%}
|
||||
|
||||
{% set final_sql_insert = doris__snapshot_merge_sql_insert(
|
||||
target = target_relation,
|
||||
source = staging_table,
|
||||
insert_cols = quoted_source_columns
|
||||
)
|
||||
%}
|
||||
|
||||
{% call statement('main') %}
|
||||
{{ final_sql_update }}
|
||||
{% endcall %}
|
||||
|
||||
{% call statement('main') %}
|
||||
{{ final_sql_insert }}
|
||||
{% endcall %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% do persist_docs(target_relation, model) %}
|
||||
|
||||
{{ run_hooks(post_hooks, inside_transaction=True) }}
|
||||
|
||||
{{ adapter.commit() }}
|
||||
|
||||
{% if staging_table is defined %}
|
||||
{% do post_snapshot(staging_table) %}
|
||||
{% endif %}
|
||||
|
||||
{{ run_hooks(post_hooks, inside_transaction=False) }}
|
||||
|
||||
{{ return({'relations': [target_relation]}) }}
|
||||
|
||||
{% endmaterialization %}
|
||||
|
||||
{% macro snapshot_check_all_get_existing_columns(node, target_exists) -%}
|
||||
{%- set query_columns = get_columns_in_query(node['compiled_sql']) -%}
|
||||
{%- if not target_exists -%}
|
||||
{# no table yet -> return whatever the query does #}
|
||||
{{ return([false, query_columns]) }}
|
||||
{%- endif -%}
|
||||
{# handle any schema changes #}
|
||||
{%- set target_table = node.get('alias', node.get('name')) -%}
|
||||
{%- set target_relation = adapter.get_relation(database=None, schema=node.schema, identifier=target_table) -%}
|
||||
{%- set existing_cols = get_columns_in_query('select * from ' ~ target_relation) -%}
|
||||
{%- set ns = namespace() -%} {# handle for-loop scoping with a namespace #}
|
||||
{%- set ns.column_added = false -%}
|
||||
|
||||
{%- set intersection = [] -%}
|
||||
{%- for col in query_columns -%}
|
||||
{%- if col in existing_cols -%}
|
||||
{%- do intersection.append(col) -%}
|
||||
{%- else -%}
|
||||
{% set ns.column_added = true %}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{{ return([ns.column_added, intersection]) }}
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,35 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__snapshot_merge_sql_update(target, source, insert_cols) -%}
|
||||
update {{ target }}, (select dbt_scd_id, dbt_change_type, dbt_valid_to from {{ source }}) as DBT_INTERNAL_SOURCE
|
||||
set {{ target }}.dbt_valid_to = DBT_INTERNAL_SOURCE.dbt_valid_to
|
||||
where DBT_INTERNAL_SOURCE.dbt_scd_id = {{ target }}.dbt_scd_id
|
||||
and DBT_INTERNAL_SOURCE.dbt_change_type = 'update'
|
||||
and {{ target }}.dbt_valid_to is null
|
||||
{% endmacro %}
|
||||
|
||||
{% macro doris__snapshot_merge_sql_insert(target, source, insert_cols) -%}
|
||||
{%- set insert_cols_csv = insert_cols | join(', ') -%}
|
||||
|
||||
insert into {{ target }} ({{ insert_cols_csv }})
|
||||
select {% for column in insert_cols -%}
|
||||
DBT_INTERNAL_SOURCE.{{ column }} {%- if not loop.last %}, {%- endif %}
|
||||
{%- endfor %}
|
||||
from {{ source }} as DBT_INTERNAL_SOURCE
|
||||
where DBT_INTERNAL_SOURCE.dbt_change_type = 'insert'
|
||||
{% endmacro %}
|
||||
@ -0,0 +1,23 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__snapshot_hash_arguments(args) -%}
|
||||
md5(concat_ws('|', {%- for arg in args -%}
|
||||
coalesce(cast({{ arg }} as char), '')
|
||||
{% if not loop.last %}, {% endif %}
|
||||
{%- endfor -%}))
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,26 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__create_table_as(temporary, relation, sql) -%}
|
||||
{% set sql_header = config.get('sql_header', none) %}
|
||||
|
||||
{{ sql_header if sql_header is not none }}
|
||||
create table {{ relation.include(database=False) }}
|
||||
{{ doris__partition_by() }}
|
||||
{{ doris__distributed_by() }}
|
||||
{{ doris__properties() }} as {{ sql }}
|
||||
{%- endmacro %}
|
||||
@ -0,0 +1,23 @@
|
||||
-- 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.
|
||||
|
||||
{% macro doris__create_view_as(relation, sql) -%}
|
||||
{%- set sql_header = config.get('sql_header', none) -%}
|
||||
|
||||
{{ sql_header if sql_header is not none }}
|
||||
create view {{ relation }} as {{ sql }};
|
||||
{%- endmacro %}
|
||||
30
extension/dbt-doris/dbt/include/doris/sample_profiles.yml
Normal file
30
extension/dbt-doris/dbt/include/doris/sample_profiles.yml
Normal file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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.
|
||||
|
||||
default:
|
||||
outputs:
|
||||
dev:
|
||||
type: doris
|
||||
host: <host>
|
||||
port: <port_num>
|
||||
username: <user>
|
||||
password: <pass>
|
||||
database: <db>
|
||||
target: dev
|
||||
1744
extension/dbt-doris/poetry.lock
generated
Normal file
1744
extension/dbt-doris/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
64
extension/dbt-doris/pyproject.toml
Normal file
64
extension/dbt-doris/pyproject.toml
Normal file
@ -0,0 +1,64 @@
|
||||
# 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.
|
||||
[tool.poetry]
|
||||
name = "dbt-doris"
|
||||
version = "0.1.0"
|
||||
description = "The doris adapter plugin for dbt"
|
||||
authors = ["long2ice <long2ice@gmail.com>"]
|
||||
include = ["dbt/include/*.sql", "dbt/include/*.yml", "dbt/include/*.md"]
|
||||
packages = [
|
||||
{ include = "dbt" },
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
dbt-core = "*"
|
||||
mysqlclient = "*"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
# Test tools
|
||||
coveralls = "*"
|
||||
pytest = "*"
|
||||
pytest-xdist = "*"
|
||||
pytest-cov = "*"
|
||||
pytest-dbt-adapter = "^0.6.0"
|
||||
# Linter tools
|
||||
mypy = "*"
|
||||
flake8 = "*"
|
||||
flake8-comprehensions = "*"
|
||||
pyproject-flake8 = "*"
|
||||
darglint = "*"
|
||||
pylint = "*"
|
||||
pygments = "*"
|
||||
bandit = "*"
|
||||
black = "*"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.black]
|
||||
line-length = 100
|
||||
target-version = ["py36", "py37", "py38", "py39"]
|
||||
|
||||
[tool.flake8]
|
||||
ignore = "E501,W503,DAR101,DAR201,DAR402"
|
||||
max-line-length = 100
|
||||
|
||||
[tool.mypy]
|
||||
pretty = true
|
||||
ignore_missing_imports = true
|
||||
19
extension/dbt-doris/test/__init__.py
Normal file
19
extension/dbt-doris/test/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# 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.
|
||||
34
extension/dbt-doris/test/doris.dbtspec
Normal file
34
extension/dbt-doris/test/doris.dbtspec
Normal file
@ -0,0 +1,34 @@
|
||||
# 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.
|
||||
|
||||
target:
|
||||
type: doris
|
||||
host: 127.0.0.1
|
||||
port: 9030
|
||||
username: root
|
||||
schema: "dbt_{{ var('_dbt_random_suffix') }}"
|
||||
|
||||
sequences:
|
||||
test_dbt_empty: empty
|
||||
test_dbt_base: base
|
||||
test_dbt_ephemeral: ephemeral
|
||||
test_dbt_incremental: incremental
|
||||
test_dbt_snapshot_strategy_timestamp: snapshot_strategy_timestamp
|
||||
test_dbt_snapshot_strategy_check_cols: snapshot_strategy_check_cols
|
||||
test_dbt_data_test: data_test
|
||||
test_dbt_schema_test: schema_test
|
||||
test_dbt_ephemeral_data_tests: data_test_ephemeral_models
|
||||
Reference in New Issue
Block a user