|
14 | 14 | See the License for the specific language governing permissions and |
15 | 15 | limitations under the License. |
16 | 16 | """ |
| 17 | +import datetime |
17 | 18 | from typing import ( |
18 | 19 | Optional, List, Set |
19 | 20 | ) |
|
24 | 25 | Dict) |
25 | 26 |
|
26 | 27 | import agate |
| 28 | +import requests |
27 | 29 |
|
28 | 30 | import dbt.exceptions |
29 | 31 | from dbt.adapters.base.relation import BaseRelation, InformationSchema |
@@ -345,3 +347,69 @@ def render_raw_columns_constraints(cls, raw_columns: Dict[str, Dict[str, Any]]) |
345 | 347 | rendered_column_constraints.append(" ".join(rendered_column_constraint)) |
346 | 348 |
|
347 | 349 | return rendered_column_constraints |
| 350 | + |
| 351 | + def get_oml_auth_token(self) -> str: |
| 352 | + if self.config.credentials.oml_auth_token_uri is None: |
| 353 | + raise dbt.exceptions.DbtRuntimeError("oml_auth_token_uri should be set to run dbt-py models") |
| 354 | + data = { |
| 355 | + "grant_type": "password", |
| 356 | + "username": self.config.credentials.user, |
| 357 | + "password": self.config.credentials.password |
| 358 | + } |
| 359 | + try: |
| 360 | + r = requests.post(url=self.config.credentials.oml_auth_token_uri, |
| 361 | + json=data) |
| 362 | + r.raise_for_status() |
| 363 | + except requests.exceptions.RequestException: |
| 364 | + raise dbt.exceptions.DbtRuntimeError("Error getting OML OAuth2.0 token") |
| 365 | + else: |
| 366 | + return r.json()["accessToken"] |
| 367 | + |
| 368 | + def submit_python_job(self, parsed_model: dict, compiled_code: str): |
| 369 | + """Submit user defined Python function |
| 370 | +
|
| 371 | + The function pyqEval when used in Oracle Autonomous Database, |
| 372 | + calls a user-defined Python function. |
| 373 | +
|
| 374 | + pyqEval(PAR_LST, OUT_FMT, SRC_NAME, SRC_OWNER, ENV_NAME) |
| 375 | +
|
| 376 | + - PAR_LST -> Parameter List |
| 377 | + - OUT_FMT -> JSON clob of the columns |
| 378 | + - ENV_NAME -> Name of conda environment |
| 379 | +
|
| 380 | +
|
| 381 | + """ |
| 382 | + identifier = parsed_model["alias"] |
| 383 | + oml_oauth_access_token = self.get_oml_auth_token() |
| 384 | + py_q_script_name = f"{identifier}_dbt_py_script" |
| 385 | + py_q_eval_output_fmt = '{"result":"number"}' |
| 386 | + py_q_eval_result_table = f"o$pt_dbt_pyqeval_{identifier}_tmp_{datetime.datetime.utcnow().strftime('%H%M%S')}" |
| 387 | + |
| 388 | + conda_env_name = parsed_model["config"].get("conda_env_name") |
| 389 | + if conda_env_name: |
| 390 | + logger.info("Custom python environment is %s", conda_env_name) |
| 391 | + py_q_eval_sql = f"""CREATE GLOBAL TEMPORARY TABLE {py_q_eval_result_table} |
| 392 | + AS SELECT * FROM TABLE(pyqEval(par_lst => NULL, |
| 393 | + out_fmt => ''{py_q_eval_output_fmt}'', |
| 394 | + scr_name => ''{py_q_script_name}'', |
| 395 | + scr_owner => NULL, |
| 396 | + env_name => ''{conda_env_name}''))""" |
| 397 | + else: |
| 398 | + py_q_eval_sql = f"""CREATE GLOBAL TEMPORARY TABLE {py_q_eval_result_table} |
| 399 | + AS SELECT * FROM TABLE(pyqEval(par_lst => NULL, |
| 400 | + out_fmt => ''{py_q_eval_output_fmt}'', |
| 401 | + scr_name => ''{py_q_script_name}'', |
| 402 | + scr_owner => NULL))""" |
| 403 | + |
| 404 | + py_exec_main_sql = f""" |
| 405 | + BEGIN |
| 406 | + sys.pyqSetAuthToken('{oml_oauth_access_token}'); |
| 407 | + sys.pyqScriptCreate('{py_q_script_name}', '{compiled_code.strip()}', FALSE, TRUE); |
| 408 | + EXECUTE IMMEDIATE '{py_q_eval_sql}'; |
| 409 | + EXECUTE IMMEDIATE 'DROP TABLE {py_q_eval_result_table}'; |
| 410 | + sys.pyqScriptDrop('{py_q_script_name}'); |
| 411 | + END; |
| 412 | + """ |
| 413 | + response, _ = self.execute(sql=py_exec_main_sql) |
| 414 | + logger.info(response) |
| 415 | + return response |
0 commit comments