|
19 | 19 | ) |
20 | 20 | from itertools import chain |
21 | 21 |
|
| 22 | +import agate |
| 23 | + |
22 | 24 | import dbt.exceptions |
23 | 25 | from dbt.adapters.base.relation import BaseRelation, InformationSchema |
24 | 26 | from dbt.adapters.base.impl import GET_CATALOG_MACRO_NAME |
|
28 | 30 | from dbt.adapters.oracle.column import OracleColumn |
29 | 31 | from dbt.adapters.oracle.relation import OracleRelation |
30 | 32 | from dbt.contracts.graph.manifest import Manifest |
| 33 | +from dbt.events import AdapterLogger |
31 | 34 |
|
32 | 35 | from dbt.exceptions import raise_compiler_error |
33 | 36 | from dbt.utils import filter_null_values |
34 | 37 |
|
| 38 | +from dbt.adapters.oracle.keyword_catalog import KEYWORDS |
| 39 | + |
| 40 | +logger = AdapterLogger("oracle") |
35 | 41 |
|
36 | | -import agate |
37 | 42 |
|
38 | 43 | COLUMNS_EQUAL_SQL = ''' |
39 | 44 | with diff_count as ( |
@@ -232,13 +237,71 @@ def list_relations_without_caching( |
232 | 237 | )) |
233 | 238 | return relations |
234 | 239 |
|
| 240 | + @staticmethod |
| 241 | + def is_valid_identifier(identifier) -> bool: |
| 242 | + """Returns True if an identifier is valid |
| 243 | +
|
| 244 | + An identifier is considered valid if the following conditions are True |
| 245 | +
|
| 246 | + 1. First character is alphabetic |
| 247 | + 2. Rest of the characters is either alphanumeric or any one of the literals '#', '$', '_' |
| 248 | +
|
| 249 | + """ |
| 250 | + # The first character should be alphabetic |
| 251 | + if not identifier[0].isalpha(): |
| 252 | + return False |
| 253 | + # Rest of the characters is either alphanumeric or any one of the literals '#', '$', '_' |
| 254 | + idx = 1 |
| 255 | + while idx < len(identifier): |
| 256 | + identifier_chr = identifier[idx] |
| 257 | + if not identifier_chr.isalnum() and identifier_chr not in ('#', '$', '_'): |
| 258 | + return False |
| 259 | + idx += 1 |
| 260 | + return True |
| 261 | + |
| 262 | + @available |
| 263 | + def should_identifier_be_quoted(self, |
| 264 | + identifier, |
| 265 | + models_column_dict=None) -> bool: |
| 266 | + """Returns True if identifier should be quoted else False |
| 267 | +
|
| 268 | + An identifier should be quoted in the following 3 cases: |
| 269 | +
|
| 270 | + - 1. Identifier is an Oracle keyword |
| 271 | +
|
| 272 | + - 2. Identifier is not valid according to the following rules |
| 273 | + - First character is alphabetic |
| 274 | + - Rest of the characters is either alphanumeric or any one of the literals '#', '$', '_' |
| 275 | +
|
| 276 | + - 3. User has enabled quoting for the column in the model configuration |
| 277 | +
|
| 278 | + """ |
| 279 | + if identifier.upper() in KEYWORDS: |
| 280 | + return True |
| 281 | + elif not self.is_valid_identifier(identifier): |
| 282 | + return True |
| 283 | + elif models_column_dict and identifier in models_column_dict: |
| 284 | + return models_column_dict[identifier].get('quote', False) |
| 285 | + elif models_column_dict and self.quote(identifier) in models_column_dict: |
| 286 | + return models_column_dict[self.quote(identifier)].get('quote', False) |
| 287 | + return False |
| 288 | + |
| 289 | + @available |
| 290 | + def check_and_quote_identifier(self, identifier, models_column_dict=None) -> str: |
| 291 | + if self.should_identifier_be_quoted(identifier, models_column_dict): |
| 292 | + return self.quote(identifier) |
| 293 | + else: |
| 294 | + return identifier |
| 295 | + |
235 | 296 | @available |
236 | 297 | def quote_seed_column( |
237 | 298 | self, column: str, quote_config: Optional[bool] |
238 | 299 | ) -> str: |
239 | 300 | quote_columns: bool = False |
240 | 301 | if isinstance(quote_config, bool): |
241 | 302 | quote_columns = quote_config |
| 303 | + elif self.should_identifier_be_quoted(column): |
| 304 | + quote_columns = True |
242 | 305 | elif quote_config is None: |
243 | 306 | pass |
244 | 307 | else: |
|
0 commit comments