Skip to content

Commit b7d27e5

Browse files
committed
Fix for bug #125
1 parent 91cdf34 commit b7d27e5

File tree

6 files changed

+216
-101
lines changed

6 files changed

+216
-101
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Configuration variables
2-
VERSION=1.7.0
2+
VERSION=1.7.1
33
PROJ_DIR?=$(shell pwd)
44
VENV_DIR?=${PROJ_DIR}/.bldenv
55
BUILD_DIR=${PROJ_DIR}/build

dbt/adapters/oracle/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
See the License for the specific language governing permissions and
1515
limitations under the License.
1616
"""
17-
version = "1.7.3"
17+
version = "1.7.4"

dbt/adapters/oracle/impl.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@
2929

3030
import dbt.exceptions
3131
from dbt.adapters.base.relation import BaseRelation, InformationSchema
32-
from dbt.adapters.base.impl import GET_CATALOG_MACRO_NAME, ConstraintSupport
32+
from dbt.adapters.base.impl import GET_CATALOG_MACRO_NAME, ConstraintSupport, GET_CATALOG_RELATIONS_MACRO_NAME, _expect_row_value
3333
from dbt.adapters.sql import SQLAdapter
3434
from dbt.adapters.base.meta import available
35+
from dbt.adapters.capability import CapabilityDict, CapabilitySupport, Support, Capability
3536
from dbt.adapters.oracle import OracleAdapterConnectionManager
3637
from dbt.adapters.oracle.column import OracleColumn
3738
from dbt.adapters.oracle.relation import OracleRelation
@@ -95,6 +96,10 @@ class OracleAdapter(SQLAdapter):
9596
ConstraintType.foreign_key: ConstraintSupport.ENFORCED,
9697
}
9798

99+
_capabilities = CapabilityDict(
100+
{Capability.SchemaMetadataByRelations: CapabilitySupport(support=Support.Full)}
101+
)
102+
98103
def debug_query(self) -> None:
99104
self.execute("select 1 as id from dual")
100105

@@ -224,6 +229,69 @@ def _get_one_catalog(
224229
results = self._catalog_filter_table(table, manifest)
225230
return results
226231

232+
def _get_one_catalog_by_relations(
233+
self,
234+
information_schema: InformationSchema,
235+
relations: List[BaseRelation],
236+
manifest: Manifest,
237+
) -> agate.Table:
238+
239+
kwargs = {
240+
"information_schema": information_schema,
241+
"relations": relations,
242+
}
243+
table = self.execute_macro(
244+
GET_CATALOG_RELATIONS_MACRO_NAME,
245+
kwargs=kwargs,
246+
# pass in the full manifest, so we get any local project
247+
# overrides
248+
manifest=manifest,
249+
)
250+
251+
# In case database is not defined, we can use the the configured database which we set as part of credentials
252+
for node in chain(manifest.nodes.values(), manifest.sources.values()):
253+
if not node.database or node.database == 'None':
254+
node.database = self.config.credentials.database
255+
256+
results = self._catalog_filter_table(table, manifest) # type: ignore[arg-type]
257+
return results
258+
259+
def get_filtered_catalog(
260+
self, manifest: Manifest, relations: Optional[Set[BaseRelation]] = None
261+
):
262+
catalogs: agate.Table
263+
if (
264+
relations is None
265+
or len(relations) > 100
266+
or not self.supports(Capability.SchemaMetadataByRelations)
267+
):
268+
# Do it the traditional way. We get the full catalog.
269+
catalogs, exceptions = self.get_catalog(manifest)
270+
else:
271+
# Do it the new way. We try to save time by selecting information
272+
# only for the exact set of relations we are interested in.
273+
catalogs, exceptions = self.get_catalog_by_relations(manifest, relations)
274+
275+
if relations and catalogs:
276+
relation_map = {
277+
(
278+
r.schema.casefold() if r.schema else None,
279+
r.identifier.casefold() if r.identifier else None,
280+
)
281+
for r in relations
282+
}
283+
284+
def in_map(row: agate.Row):
285+
s = _expect_row_value("table_schema", row)
286+
i = _expect_row_value("table_name", row)
287+
s = s.casefold() if s is not None else None
288+
i = i.casefold() if i is not None else None
289+
return (s, i) in relation_map
290+
291+
catalogs = catalogs.where(in_map)
292+
293+
return catalogs, exceptions
294+
227295
def list_relations_without_caching(
228296
self, schema_relation: BaseRelation,
229297
) -> List[BaseRelation]:

dbt/include/oracle/macros/catalog.sql

Lines changed: 143 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -14,64 +14,9 @@
1414
See the License for the specific language governing permissions and
1515
limitations under the License.
1616
#}
17-
{% macro oracle__get_catalog(information_schema, schemas) -%}
18-
19-
{%- call statement('catalog', fetch_result=True) -%}
20-
{#
21-
If the user has multiple databases set and the first one is wrong, this will fail.
22-
But we won't fail in the case where there are multiple quoting-difference-only dbs, which is better.
23-
#}
24-
{% set database = information_schema.database %}
25-
{% if database == 'None' or database is undefined or database is none %}
26-
{% set database = get_database_name() %}
27-
{% endif %}
28-
{{ adapter.verify_database(database) }}
2917

30-
with columns as (
31-
select
32-
SYS_CONTEXT('userenv', 'DB_NAME') table_catalog,
33-
owner table_schema,
34-
table_name,
35-
column_name,
36-
data_type,
37-
data_type_mod,
38-
decode(data_type_owner, null, TO_CHAR(null), SYS_CONTEXT('userenv', 'DB_NAME')) domain_catalog,
39-
data_type_owner domain_schema,
40-
data_length character_maximum_length,
41-
data_length character_octet_length,
42-
data_length,
43-
data_precision numeric_precision,
44-
data_scale numeric_scale,
45-
nullable is_nullable,
46-
coalesce(column_id, 0) ordinal_position,
47-
default_length,
48-
data_default column_default,
49-
num_distinct,
50-
low_value,
51-
high_value,
52-
density,
53-
num_nulls,
54-
num_buckets,
55-
last_analyzed,
56-
sample_size,
57-
SYS_CONTEXT('userenv', 'DB_NAME') character_set_catalog,
58-
'SYS' character_set_schema,
59-
SYS_CONTEXT('userenv', 'DB_NAME') collation_catalog,
60-
'SYS' collation_schema,
61-
character_set_name,
62-
char_col_decl_length,
63-
global_stats,
64-
user_stats,
65-
avg_col_len,
66-
char_length,
67-
char_used,
68-
v80_fmt_image,
69-
data_upgraded,
70-
histogram
71-
from sys.all_tab_columns
72-
),
73-
tables as
74-
(select SYS_CONTEXT('userenv', 'DB_NAME') table_catalog,
18+
{% macro oracle__get_catalog_tables_sql(information_schema) -%}
19+
select SYS_CONTEXT('userenv', 'DB_NAME') table_catalog,
7520
owner table_schema,
7621
table_name,
7722
case
@@ -82,7 +27,7 @@
8227
else 'BASE TABLE'
8328
end table_type
8429
from sys.all_tables
85-
where upper(table_name) not in (select upper(mview_name) from sys.all_mviews)
30+
where upper(table_name) not in (select upper(mview_name) from sys.all_mviews)
8631
union all
8732
select SYS_CONTEXT('userenv', 'DB_NAME'),
8833
owner,
@@ -95,44 +40,146 @@
9540
mview_name,
9641
'MATERIALIZED VIEW'
9742
from sys.all_mviews
98-
)
99-
select
100-
tables.table_catalog as "table_database",
101-
tables.table_schema as "table_schema",
102-
tables.table_name as "table_name",
103-
tables.table_type as "table_type",
104-
all_tab_comments.comments as "table_comment",
105-
columns.column_name as "column_name",
106-
ordinal_position as "column_index",
107-
case
108-
when data_type like '%CHAR%'
109-
then data_type || '(' || cast(char_length as varchar(10)) || ')'
110-
else data_type
111-
end as "column_type",
112-
all_col_comments.comments as "column_comment",
113-
tables.table_schema as "table_owner"
114-
from tables
115-
inner join columns on upper(columns.table_catalog) = upper(tables.table_catalog)
116-
and upper(columns.table_schema) = upper(tables.table_schema)
117-
and upper(columns.table_name) = upper(tables.table_name)
118-
left join all_tab_comments
119-
on upper(all_tab_comments.owner) = upper(tables.table_schema)
120-
and upper(all_tab_comments.table_name) = upper(tables.table_name)
121-
left join all_col_comments
122-
on upper(all_col_comments.owner) = upper(columns.table_schema)
123-
and upper(all_col_comments.table_name) = upper(columns.table_name)
124-
and upper(all_col_comments.column_name) = upper(columns.column_name)
125-
where (
126-
{%- for schema in schemas -%}
127-
upper(tables.table_schema) = upper('{{ schema }}'){%- if not loop.last %} or {% endif -%}
128-
{%- endfor -%}
129-
)
130-
order by
131-
tables.table_schema,
132-
tables.table_name,
133-
ordinal_position
134-
{%- endcall -%}
43+
{%- endmacro %}
44+
45+
{% macro oracle__get_catalog_columns_sql(information_schema) -%}
46+
select
47+
SYS_CONTEXT('userenv', 'DB_NAME') table_catalog,
48+
owner table_schema,
49+
table_name,
50+
column_name,
51+
data_type,
52+
data_type_mod,
53+
decode(data_type_owner, null, TO_CHAR(null), SYS_CONTEXT('userenv', 'DB_NAME')) domain_catalog,
54+
data_type_owner domain_schema,
55+
data_length character_maximum_length,
56+
data_length character_octet_length,
57+
data_length,
58+
data_precision numeric_precision,
59+
data_scale numeric_scale,
60+
nullable is_nullable,
61+
coalesce(column_id, 0) ordinal_position,
62+
default_length,
63+
data_default column_default,
64+
num_distinct,
65+
low_value,
66+
high_value,
67+
density,
68+
num_nulls,
69+
num_buckets,
70+
last_analyzed,
71+
sample_size,
72+
SYS_CONTEXT('userenv', 'DB_NAME') character_set_catalog,
73+
'SYS' character_set_schema,
74+
SYS_CONTEXT('userenv', 'DB_NAME') collation_catalog,
75+
'SYS' collation_schema,
76+
character_set_name,
77+
char_col_decl_length,
78+
global_stats,
79+
user_stats,
80+
avg_col_len,
81+
char_length,
82+
char_used,
83+
v80_fmt_image,
84+
data_upgraded,
85+
histogram
86+
from sys.all_tab_columns
87+
{%- endmacro %}
88+
89+
{% macro oracle__get_catalog_results_sql() -%}
90+
select
91+
tables.table_catalog as "table_database",
92+
tables.table_schema as "table_schema",
93+
tables.table_name as "table_name",
94+
tables.table_type as "table_type",
95+
all_tab_comments.comments as "table_comment",
96+
columns.column_name as "column_name",
97+
ordinal_position as "column_index",
98+
case
99+
when data_type like '%CHAR%'
100+
then data_type || '(' || cast(char_length as varchar(10)) || ')'
101+
else data_type
102+
end as "column_type",
103+
all_col_comments.comments as "column_comment",
104+
tables.table_schema as "table_owner"
105+
from tables
106+
inner join columns on upper(columns.table_catalog) = upper(tables.table_catalog)
107+
and upper(columns.table_schema) = upper(tables.table_schema)
108+
and upper(columns.table_name) = upper(tables.table_name)
109+
left join all_tab_comments
110+
on upper(all_tab_comments.owner) = upper(tables.table_schema)
111+
and upper(all_tab_comments.table_name) = upper(tables.table_name)
112+
left join all_col_comments
113+
on upper(all_col_comments.owner) = upper(columns.table_schema)
114+
and upper(all_col_comments.table_name) = upper(columns.table_name)
115+
and upper(all_col_comments.column_name) = upper(columns.column_name)
116+
{%- endmacro %}
117+
118+
{% macro oracle__get_catalog_schemas_where_clause_sql(schemas) -%}
119+
where (
120+
{%- for schema in schemas -%}
121+
upper(tables.table_schema) = upper('{{ schema }}'){%- if not loop.last %} or {% endif -%}
122+
{%- endfor -%}
123+
)
124+
{%- endmacro %}
125+
126+
{% macro oracle__get_catalog_relations_where_clause_sql(relations) -%}
127+
where (
128+
{%- for relation in relations -%}
129+
{% if relation.schema and relation.identifier %}
130+
(
131+
upper(tables.table_schema) = upper('{{ relation.schema }}')
132+
and upper(tables.table_name) = upper('{{ relation.identifier }}')
133+
)
134+
{% elif relation.schema %}
135+
(
136+
upper(tables.table_schema) = upper('{{ relation.schema }}')
137+
)
138+
{% else %}
139+
{% do exceptions.raise_compiler_error(
140+
'`get_catalog_relations` requires a list of relations, each with a schema'
141+
) %}
142+
{% endif %}
143+
144+
{%- if not loop.last %} or {% endif -%}
145+
{%- endfor -%}
146+
)
147+
{%- endmacro %}
148+
149+
{% macro oracle__get_catalog(information_schema, schemas) -%}
150+
{% set query %}
151+
with tables as (
152+
{{ oracle__get_catalog_tables_sql(information_schema) }}
153+
),
154+
columns as (
155+
{{ oracle__get_catalog_columns_sql(information_schema) }}
156+
)
157+
{{ oracle__get_catalog_results_sql() }}
158+
{{ oracle__get_catalog_schemas_where_clause_sql(schemas) }}
159+
order by
160+
tables.table_schema,
161+
tables.table_name,
162+
ordinal_position
163+
{%- endset -%}
164+
{{ return(run_query(query)) }}
165+
{%- endmacro %}
166+
167+
{% macro oracle__get_catalog_relations(information_schema, relations) -%}
168+
{% set query %}
169+
with tables as (
170+
{{ oracle__get_catalog_tables_sql(information_schema) }}
171+
),
172+
columns as (
173+
{{ oracle__get_catalog_columns_sql(information_schema) }}
174+
)
175+
{{ oracle__get_catalog_results_sql() }}
176+
{{ oracle__get_catalog_relations_where_clause_sql(relations) }}
177+
order by
178+
tables.table_schema,
179+
tables.table_name,
180+
ordinal_position
181+
{%- endset -%}
135182

136-
{{ return(load_result('catalog').table) }}
183+
{{ return(run_query(query)) }}
137184

138185
{%- endmacro %}

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = dbt-oracle
3-
version = 1.7.0
3+
version = 1.7.1
44
description = dbt (data build tool) adapter for Oracle Autonomous Database
55
long_description = file: README.md
66
long_description_content_type = text/markdown

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060

6161
url = 'https://github.com/oracle/dbt-oracle'
6262

63-
VERSION = '1.7.0'
63+
VERSION = '1.7.1'
6464
setup(
6565
author="Oracle",
6666
python_requires='>=3.8',

0 commit comments

Comments
 (0)