dbt-adapters 1.22.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. dbt/adapters/__about__.py +1 -0
  2. dbt/adapters/__init__.py +8 -0
  3. dbt/adapters/base/README.md +13 -0
  4. dbt/adapters/base/__init__.py +16 -0
  5. dbt/adapters/base/column.py +173 -0
  6. dbt/adapters/base/connections.py +429 -0
  7. dbt/adapters/base/impl.py +2036 -0
  8. dbt/adapters/base/meta.py +150 -0
  9. dbt/adapters/base/plugin.py +32 -0
  10. dbt/adapters/base/query_headers.py +106 -0
  11. dbt/adapters/base/relation.py +648 -0
  12. dbt/adapters/cache.py +521 -0
  13. dbt/adapters/capability.py +63 -0
  14. dbt/adapters/catalogs/__init__.py +14 -0
  15. dbt/adapters/catalogs/_client.py +54 -0
  16. dbt/adapters/catalogs/_constants.py +1 -0
  17. dbt/adapters/catalogs/_exceptions.py +39 -0
  18. dbt/adapters/catalogs/_integration.py +113 -0
  19. dbt/adapters/clients/__init__.py +0 -0
  20. dbt/adapters/clients/jinja.py +24 -0
  21. dbt/adapters/contracts/__init__.py +0 -0
  22. dbt/adapters/contracts/connection.py +229 -0
  23. dbt/adapters/contracts/macros.py +11 -0
  24. dbt/adapters/contracts/relation.py +160 -0
  25. dbt/adapters/events/README.md +51 -0
  26. dbt/adapters/events/__init__.py +0 -0
  27. dbt/adapters/events/adapter_types_pb2.py +2 -0
  28. dbt/adapters/events/base_types.py +36 -0
  29. dbt/adapters/events/logging.py +83 -0
  30. dbt/adapters/events/types.py +436 -0
  31. dbt/adapters/exceptions/__init__.py +40 -0
  32. dbt/adapters/exceptions/alias.py +24 -0
  33. dbt/adapters/exceptions/cache.py +68 -0
  34. dbt/adapters/exceptions/compilation.py +269 -0
  35. dbt/adapters/exceptions/connection.py +16 -0
  36. dbt/adapters/exceptions/database.py +51 -0
  37. dbt/adapters/factory.py +264 -0
  38. dbt/adapters/protocol.py +150 -0
  39. dbt/adapters/py.typed +0 -0
  40. dbt/adapters/record/__init__.py +2 -0
  41. dbt/adapters/record/base.py +291 -0
  42. dbt/adapters/record/cursor/cursor.py +69 -0
  43. dbt/adapters/record/cursor/description.py +37 -0
  44. dbt/adapters/record/cursor/execute.py +39 -0
  45. dbt/adapters/record/cursor/fetchall.py +69 -0
  46. dbt/adapters/record/cursor/fetchmany.py +23 -0
  47. dbt/adapters/record/cursor/fetchone.py +23 -0
  48. dbt/adapters/record/cursor/rowcount.py +23 -0
  49. dbt/adapters/record/handle.py +55 -0
  50. dbt/adapters/record/serialization.py +115 -0
  51. dbt/adapters/reference_keys.py +39 -0
  52. dbt/adapters/relation_configs/README.md +25 -0
  53. dbt/adapters/relation_configs/__init__.py +12 -0
  54. dbt/adapters/relation_configs/config_base.py +46 -0
  55. dbt/adapters/relation_configs/config_change.py +26 -0
  56. dbt/adapters/relation_configs/config_validation.py +57 -0
  57. dbt/adapters/sql/__init__.py +2 -0
  58. dbt/adapters/sql/connections.py +263 -0
  59. dbt/adapters/sql/impl.py +286 -0
  60. dbt/adapters/utils.py +69 -0
  61. dbt/include/__init__.py +3 -0
  62. dbt/include/global_project/__init__.py +4 -0
  63. dbt/include/global_project/dbt_project.yml +7 -0
  64. dbt/include/global_project/docs/overview.md +43 -0
  65. dbt/include/global_project/macros/adapters/apply_grants.sql +167 -0
  66. dbt/include/global_project/macros/adapters/columns.sql +144 -0
  67. dbt/include/global_project/macros/adapters/freshness.sql +32 -0
  68. dbt/include/global_project/macros/adapters/indexes.sql +41 -0
  69. dbt/include/global_project/macros/adapters/metadata.sql +105 -0
  70. dbt/include/global_project/macros/adapters/persist_docs.sql +33 -0
  71. dbt/include/global_project/macros/adapters/relation.sql +84 -0
  72. dbt/include/global_project/macros/adapters/schema.sql +20 -0
  73. dbt/include/global_project/macros/adapters/show.sql +26 -0
  74. dbt/include/global_project/macros/adapters/timestamps.sql +52 -0
  75. dbt/include/global_project/macros/adapters/validate_sql.sql +10 -0
  76. dbt/include/global_project/macros/etc/datetime.sql +62 -0
  77. dbt/include/global_project/macros/etc/statement.sql +52 -0
  78. dbt/include/global_project/macros/generic_test_sql/accepted_values.sql +27 -0
  79. dbt/include/global_project/macros/generic_test_sql/not_null.sql +9 -0
  80. dbt/include/global_project/macros/generic_test_sql/relationships.sql +23 -0
  81. dbt/include/global_project/macros/generic_test_sql/unique.sql +12 -0
  82. dbt/include/global_project/macros/get_custom_name/get_custom_alias.sql +36 -0
  83. dbt/include/global_project/macros/get_custom_name/get_custom_database.sql +32 -0
  84. dbt/include/global_project/macros/get_custom_name/get_custom_schema.sql +60 -0
  85. dbt/include/global_project/macros/materializations/configs.sql +21 -0
  86. dbt/include/global_project/macros/materializations/functions/aggregate.sql +65 -0
  87. dbt/include/global_project/macros/materializations/functions/function.sql +20 -0
  88. dbt/include/global_project/macros/materializations/functions/helpers.sql +20 -0
  89. dbt/include/global_project/macros/materializations/functions/scalar.sql +69 -0
  90. dbt/include/global_project/macros/materializations/hooks.sql +35 -0
  91. dbt/include/global_project/macros/materializations/models/clone/can_clone_table.sql +7 -0
  92. dbt/include/global_project/macros/materializations/models/clone/clone.sql +67 -0
  93. dbt/include/global_project/macros/materializations/models/clone/create_or_replace_clone.sql +7 -0
  94. dbt/include/global_project/macros/materializations/models/incremental/column_helpers.sql +80 -0
  95. dbt/include/global_project/macros/materializations/models/incremental/incremental.sql +99 -0
  96. dbt/include/global_project/macros/materializations/models/incremental/is_incremental.sql +13 -0
  97. dbt/include/global_project/macros/materializations/models/incremental/merge.sql +120 -0
  98. dbt/include/global_project/macros/materializations/models/incremental/on_schema_change.sql +159 -0
  99. dbt/include/global_project/macros/materializations/models/incremental/strategies.sql +92 -0
  100. dbt/include/global_project/macros/materializations/models/materialized_view.sql +121 -0
  101. dbt/include/global_project/macros/materializations/models/table.sql +64 -0
  102. dbt/include/global_project/macros/materializations/models/view.sql +72 -0
  103. dbt/include/global_project/macros/materializations/seeds/helpers.sql +128 -0
  104. dbt/include/global_project/macros/materializations/seeds/seed.sql +60 -0
  105. dbt/include/global_project/macros/materializations/snapshots/helpers.sql +345 -0
  106. dbt/include/global_project/macros/materializations/snapshots/snapshot.sql +109 -0
  107. dbt/include/global_project/macros/materializations/snapshots/snapshot_merge.sql +34 -0
  108. dbt/include/global_project/macros/materializations/snapshots/strategies.sql +184 -0
  109. dbt/include/global_project/macros/materializations/tests/helpers.sql +44 -0
  110. dbt/include/global_project/macros/materializations/tests/test.sql +66 -0
  111. dbt/include/global_project/macros/materializations/tests/unit.sql +40 -0
  112. dbt/include/global_project/macros/materializations/tests/where_subquery.sql +15 -0
  113. dbt/include/global_project/macros/python_model/python.sql +114 -0
  114. dbt/include/global_project/macros/relations/column/columns_spec_ddl.sql +89 -0
  115. dbt/include/global_project/macros/relations/create.sql +23 -0
  116. dbt/include/global_project/macros/relations/create_backup.sql +17 -0
  117. dbt/include/global_project/macros/relations/create_intermediate.sql +17 -0
  118. dbt/include/global_project/macros/relations/drop.sql +41 -0
  119. dbt/include/global_project/macros/relations/drop_backup.sql +14 -0
  120. dbt/include/global_project/macros/relations/materialized_view/alter.sql +55 -0
  121. dbt/include/global_project/macros/relations/materialized_view/create.sql +10 -0
  122. dbt/include/global_project/macros/relations/materialized_view/drop.sql +14 -0
  123. dbt/include/global_project/macros/relations/materialized_view/refresh.sql +9 -0
  124. dbt/include/global_project/macros/relations/materialized_view/rename.sql +10 -0
  125. dbt/include/global_project/macros/relations/materialized_view/replace.sql +10 -0
  126. dbt/include/global_project/macros/relations/rename.sql +35 -0
  127. dbt/include/global_project/macros/relations/rename_intermediate.sql +14 -0
  128. dbt/include/global_project/macros/relations/replace.sql +50 -0
  129. dbt/include/global_project/macros/relations/schema.sql +8 -0
  130. dbt/include/global_project/macros/relations/table/create.sql +60 -0
  131. dbt/include/global_project/macros/relations/table/drop.sql +14 -0
  132. dbt/include/global_project/macros/relations/table/rename.sql +10 -0
  133. dbt/include/global_project/macros/relations/table/replace.sql +10 -0
  134. dbt/include/global_project/macros/relations/view/create.sql +27 -0
  135. dbt/include/global_project/macros/relations/view/drop.sql +14 -0
  136. dbt/include/global_project/macros/relations/view/rename.sql +10 -0
  137. dbt/include/global_project/macros/relations/view/replace.sql +66 -0
  138. dbt/include/global_project/macros/unit_test_sql/get_fixture_sql.sql +107 -0
  139. dbt/include/global_project/macros/utils/any_value.sql +9 -0
  140. dbt/include/global_project/macros/utils/array_append.sql +8 -0
  141. dbt/include/global_project/macros/utils/array_concat.sql +7 -0
  142. dbt/include/global_project/macros/utils/array_construct.sql +12 -0
  143. dbt/include/global_project/macros/utils/bool_or.sql +9 -0
  144. dbt/include/global_project/macros/utils/cast.sql +7 -0
  145. dbt/include/global_project/macros/utils/cast_bool_to_text.sql +7 -0
  146. dbt/include/global_project/macros/utils/concat.sql +7 -0
  147. dbt/include/global_project/macros/utils/data_types.sql +129 -0
  148. dbt/include/global_project/macros/utils/date.sql +10 -0
  149. dbt/include/global_project/macros/utils/date_spine.sql +75 -0
  150. dbt/include/global_project/macros/utils/date_trunc.sql +7 -0
  151. dbt/include/global_project/macros/utils/dateadd.sql +14 -0
  152. dbt/include/global_project/macros/utils/datediff.sql +14 -0
  153. dbt/include/global_project/macros/utils/equals.sql +14 -0
  154. dbt/include/global_project/macros/utils/escape_single_quotes.sql +8 -0
  155. dbt/include/global_project/macros/utils/except.sql +9 -0
  156. dbt/include/global_project/macros/utils/generate_series.sql +53 -0
  157. dbt/include/global_project/macros/utils/hash.sql +7 -0
  158. dbt/include/global_project/macros/utils/intersect.sql +9 -0
  159. dbt/include/global_project/macros/utils/last_day.sql +15 -0
  160. dbt/include/global_project/macros/utils/length.sql +11 -0
  161. dbt/include/global_project/macros/utils/listagg.sql +30 -0
  162. dbt/include/global_project/macros/utils/literal.sql +7 -0
  163. dbt/include/global_project/macros/utils/position.sql +11 -0
  164. dbt/include/global_project/macros/utils/replace.sql +14 -0
  165. dbt/include/global_project/macros/utils/right.sql +12 -0
  166. dbt/include/global_project/macros/utils/safe_cast.sql +9 -0
  167. dbt/include/global_project/macros/utils/split_part.sql +26 -0
  168. dbt/include/global_project/tests/generic/builtin.sql +30 -0
  169. dbt/include/py.typed +0 -0
  170. dbt_adapters-1.22.2.dist-info/METADATA +124 -0
  171. dbt_adapters-1.22.2.dist-info/RECORD +173 -0
  172. dbt_adapters-1.22.2.dist-info/WHEEL +4 -0
  173. dbt_adapters-1.22.2.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1 @@
1
+ version = "1.22.2"
@@ -0,0 +1,8 @@
1
+ """
2
+ This adds all subdirectories of directories on `sys.path` to this package’s `__path__` .
3
+ It effectively combines all adapters into a single namespace (dbt.adapter).
4
+ """
5
+
6
+ from pkgutil import extend_path
7
+
8
+ __path__ = extend_path(__path__, __name__)
@@ -0,0 +1,13 @@
1
+ ## Base adapters
2
+
3
+ ### impl.py
4
+
5
+ The class `SQLAdapter` in [base/imply.py](https://github.com/dbt-labs/dbt-core/blob/main/core/dbt/adapters/base/impl.py)
6
+ is a (mostly) abstract object that adapter objects inherit from.
7
+ The base class scaffolds out methods that every adapter project
8
+ usually should implement for smooth communication between dbt and database.
9
+
10
+ Some target databases require more or fewer methods--
11
+ it all depends on what the warehouse's featureset is.
12
+
13
+ Look into the class for function-level comments.
@@ -0,0 +1,16 @@
1
+ from dbt.adapters.base.meta import available
2
+ from dbt.adapters.base.column import Column
3
+ from dbt.adapters.base.connections import BaseConnectionManager
4
+ from dbt.adapters.base.impl import (
5
+ AdapterConfig,
6
+ BaseAdapter,
7
+ ConstraintSupport,
8
+ PythonJobHelper,
9
+ )
10
+ from dbt.adapters.base.plugin import AdapterPlugin
11
+ from dbt.adapters.base.relation import (
12
+ BaseRelation,
13
+ RelationType,
14
+ SchemaSearchMap,
15
+ AdapterTrackingRelationInfo,
16
+ )
@@ -0,0 +1,173 @@
1
+ from dataclasses import dataclass
2
+ import re
3
+ from typing import Any, ClassVar, Dict, Optional
4
+
5
+ from dbt_common.exceptions import DbtRuntimeError
6
+
7
+
8
+ @dataclass
9
+ class Column:
10
+ # Note: This is automatically used by contract code
11
+ # No-op conversions (INTEGER => INT) have been removed.
12
+ # Any adapter that wants to take advantage of "translate_type"
13
+ # should create a ClassVar with the appropriate conversions.
14
+ TYPE_LABELS: ClassVar[Dict[str, str]] = {
15
+ "STRING": "TEXT",
16
+ }
17
+ column: str
18
+ dtype: str
19
+ char_size: Optional[int] = None
20
+ numeric_precision: Optional[Any] = None
21
+ numeric_scale: Optional[Any] = None
22
+
23
+ @classmethod
24
+ def translate_type(cls, dtype: str) -> str:
25
+ return cls.TYPE_LABELS.get(dtype.upper(), dtype)
26
+
27
+ @classmethod
28
+ def create(cls, name, label_or_dtype: str) -> "Column":
29
+ column_type = cls.translate_type(label_or_dtype)
30
+ return cls(name, column_type)
31
+
32
+ @property
33
+ def name(self) -> str:
34
+ return self.column
35
+
36
+ @property
37
+ def quoted(self) -> str:
38
+ return '"{}"'.format(self.column)
39
+
40
+ @property
41
+ def data_type(self) -> str:
42
+ if self.is_string():
43
+ return self.string_type(self.string_size())
44
+ elif self.is_numeric():
45
+ return self.numeric_type(self.dtype, self.numeric_precision, self.numeric_scale)
46
+ else:
47
+ return self.dtype
48
+
49
+ @property
50
+ def expanded_data_type(self) -> str:
51
+ """
52
+ Adapter-overridable data type string that may include adapter-specific
53
+ expansions (e.g. collation clauses) for use in DDL/schema comparisons.
54
+
55
+ By default, this is identical to `data_type`.
56
+ """
57
+ return self.data_type
58
+
59
+ def is_string(self) -> bool:
60
+ return self.dtype.lower() in [
61
+ "text",
62
+ "character varying",
63
+ "character",
64
+ "varchar",
65
+ ]
66
+
67
+ def is_number(self):
68
+ return any([self.is_integer(), self.is_numeric(), self.is_float()])
69
+
70
+ def is_float(self):
71
+ return self.dtype.lower() in [
72
+ # floats
73
+ "real",
74
+ "float4",
75
+ "float",
76
+ "double precision",
77
+ "float8",
78
+ "double",
79
+ ]
80
+
81
+ def is_integer(self) -> bool:
82
+ return self.dtype.lower() in [
83
+ # real types
84
+ "smallint",
85
+ "integer",
86
+ "bigint",
87
+ "smallserial",
88
+ "serial",
89
+ "bigserial",
90
+ # aliases
91
+ "int2",
92
+ "int4",
93
+ "int8",
94
+ "serial2",
95
+ "serial4",
96
+ "serial8",
97
+ ]
98
+
99
+ def is_numeric(self) -> bool:
100
+ return self.dtype.lower() in ["numeric", "decimal"]
101
+
102
+ def string_size(self) -> int:
103
+ if not self.is_string():
104
+ raise DbtRuntimeError("Called string_size() on non-string field!")
105
+
106
+ if self.dtype == "text" or self.char_size is None:
107
+ # char_size should never be None. Handle it reasonably just in case
108
+ return 256
109
+ else:
110
+ return int(self.char_size)
111
+
112
+ def can_expand_to(self, other_column: "Column") -> bool:
113
+ """returns True if this column can be expanded to the size of the
114
+ other column"""
115
+ if not self.is_string() or not other_column.is_string():
116
+ return False
117
+
118
+ return other_column.string_size() > self.string_size()
119
+
120
+ def literal(self, value: Any) -> str:
121
+ return "{}::{}".format(value, self.data_type)
122
+
123
+ @classmethod
124
+ def string_type(cls, size: int) -> str:
125
+ return "character varying({})".format(size)
126
+
127
+ @classmethod
128
+ def numeric_type(cls, dtype: str, precision: Any, scale: Any) -> str:
129
+ # This could be decimal(...), numeric(...), number(...)
130
+ # Just use whatever was fed in here -- don't try to get too clever
131
+ if precision is None or scale is None:
132
+ return dtype
133
+ else:
134
+ return "{}({},{})".format(dtype, precision, scale)
135
+
136
+ @classmethod
137
+ def from_description(cls, name: str, raw_data_type: str) -> "Column":
138
+ match = re.match(r"([^(]+)(\([^)]+\))?", raw_data_type)
139
+ if match is None:
140
+ raise DbtRuntimeError(f'Could not interpret data type "{raw_data_type}"')
141
+ data_type, size_info = match.groups()
142
+ char_size = None
143
+ numeric_precision = None
144
+ numeric_scale = None
145
+ if size_info is not None:
146
+ # strip out the parentheses
147
+ size_info = size_info[1:-1]
148
+ parts = size_info.split(",")
149
+ if len(parts) == 1:
150
+ try:
151
+ char_size = int(parts[0])
152
+ except ValueError:
153
+ raise DbtRuntimeError(
154
+ f'Could not interpret data_type "{raw_data_type}": '
155
+ f'could not convert "{parts[0]}" to an integer'
156
+ )
157
+ elif len(parts) == 2:
158
+ try:
159
+ numeric_precision = int(parts[0])
160
+ except ValueError:
161
+ raise DbtRuntimeError(
162
+ f'Could not interpret data_type "{raw_data_type}": '
163
+ f'could not convert "{parts[0]}" to an integer'
164
+ )
165
+ try:
166
+ numeric_scale = int(parts[1])
167
+ except ValueError:
168
+ raise DbtRuntimeError(
169
+ f'Could not interpret data_type "{raw_data_type}": '
170
+ f'could not convert "{parts[1]}" to an integer'
171
+ )
172
+
173
+ return cls(name, data_type, char_size, numeric_precision, numeric_scale)
@@ -0,0 +1,429 @@
1
+ import abc
2
+ import os
3
+ import sys
4
+ from time import sleep
5
+ import traceback
6
+ from multiprocessing.context import SpawnContext
7
+ from multiprocessing.synchronize import RLock
8
+ from threading import get_ident
9
+ from typing import (
10
+ Any,
11
+ Callable,
12
+ ContextManager,
13
+ Dict,
14
+ Hashable,
15
+ Iterable,
16
+ List,
17
+ Optional,
18
+ Tuple,
19
+ Type,
20
+ Union,
21
+ TYPE_CHECKING,
22
+ )
23
+
24
+ from dbt_common.events.contextvars import get_node_info
25
+ from dbt_common.events.functions import fire_event
26
+ from dbt_common.exceptions import DbtInternalError, NotImplementedError
27
+ from dbt_common.utils import cast_to_str
28
+
29
+ from dbt.adapters.base.query_headers import MacroQueryStringSetter
30
+ from dbt.adapters.contracts.connection import (
31
+ AdapterRequiredConfig,
32
+ AdapterResponse,
33
+ Connection,
34
+ ConnectionState,
35
+ Identifier,
36
+ LazyHandle,
37
+ )
38
+ from dbt.adapters.events.logging import AdapterLogger
39
+ from dbt.adapters.events.types import (
40
+ ConnectionClosed,
41
+ ConnectionClosedInCleanup,
42
+ ConnectionLeftOpen,
43
+ ConnectionLeftOpenInCleanup,
44
+ ConnectionReused,
45
+ NewConnection,
46
+ Rollback,
47
+ RollbackFailed,
48
+ )
49
+ from dbt.adapters.exceptions import FailedToConnectError, InvalidConnectionError
50
+
51
+ if TYPE_CHECKING:
52
+ import agate
53
+
54
+
55
+ SleepTime = Union[int, float] # As taken by time.sleep.
56
+ AdapterHandle = Any # Adapter connection handle objects can be any class.
57
+
58
+
59
+ class BaseConnectionManager(metaclass=abc.ABCMeta):
60
+ """Methods to implement:
61
+ - exception_handler
62
+ - cancel_open
63
+ - open
64
+ - begin
65
+ - commit
66
+ - clear_transaction
67
+ - execute
68
+
69
+ You must also set the 'TYPE' class attribute with a class-unique constant
70
+ string.
71
+ """
72
+
73
+ TYPE: str = NotImplemented
74
+
75
+ def __init__(self, profile: AdapterRequiredConfig, mp_context: SpawnContext) -> None:
76
+ self.profile = profile
77
+ self.thread_connections: Dict[Hashable, Connection] = {}
78
+ self.lock: RLock = mp_context.RLock()
79
+ self.query_header: Optional[MacroQueryStringSetter] = None
80
+
81
+ def set_query_header(self, query_header_context: Dict[str, Any]) -> None:
82
+ self.query_header = MacroQueryStringSetter(self.profile, query_header_context)
83
+
84
+ @staticmethod
85
+ def get_thread_identifier() -> Hashable:
86
+ # note that get_ident() may be re-used, but we should never experience
87
+ # that within a single process
88
+ return os.getpid(), get_ident()
89
+
90
+ def get_thread_connection(self) -> Connection:
91
+ key = self.get_thread_identifier()
92
+ with self.lock:
93
+ if key not in self.thread_connections:
94
+ raise InvalidConnectionError(key, list(self.thread_connections))
95
+ return self.thread_connections[key]
96
+
97
+ def set_thread_connection(self, conn: Connection) -> None:
98
+ key = self.get_thread_identifier()
99
+ if key in self.thread_connections:
100
+ raise DbtInternalError("In set_thread_connection, existing connection exists for {}")
101
+ self.thread_connections[key] = conn
102
+
103
+ def get_if_exists(self) -> Optional[Connection]:
104
+ key = self.get_thread_identifier()
105
+ with self.lock:
106
+ return self.thread_connections.get(key)
107
+
108
+ def clear_thread_connection(self) -> None:
109
+ key = self.get_thread_identifier()
110
+ with self.lock:
111
+ if key in self.thread_connections:
112
+ del self.thread_connections[key]
113
+
114
+ def clear_transaction(self) -> None:
115
+ """Clear any existing transactions."""
116
+ conn = self.get_thread_connection()
117
+ if conn is not None:
118
+ if conn.transaction_open:
119
+ self._rollback(conn)
120
+ self.begin()
121
+ self.commit()
122
+
123
+ def rollback_if_open(self) -> None:
124
+ conn = self.get_if_exists()
125
+ if conn is not None and conn.handle and conn.transaction_open:
126
+ self._rollback(conn)
127
+
128
+ @abc.abstractmethod
129
+ def exception_handler(self, sql: str) -> ContextManager:
130
+ """Create a context manager that handles exceptions caused by database
131
+ interactions.
132
+
133
+ :param str sql: The SQL string that the block inside the context
134
+ manager is executing.
135
+ :return: A context manager that handles exceptions raised by the
136
+ underlying database.
137
+ """
138
+ raise NotImplementedError("`exception_handler` is not implemented for this adapter!")
139
+
140
+ def set_connection_name(self, name: Optional[str] = None) -> Connection:
141
+ """Called by 'acquire_connection' in BaseAdapter, which is called by
142
+ 'connection_named'.
143
+ Creates a connection for this thread if one doesn't already
144
+ exist, and will rename an existing connection."""
145
+
146
+ conn_name: str = "master" if name is None else name
147
+
148
+ # Get a connection for this thread
149
+ conn = self.get_if_exists()
150
+
151
+ if conn and conn.name == conn_name and conn.state == "open":
152
+ # Found a connection and nothing to do, so just return it
153
+ return conn
154
+
155
+ if conn is None:
156
+ # Create a new connection
157
+ conn = Connection(
158
+ type=Identifier(self.TYPE),
159
+ name=conn_name,
160
+ state=ConnectionState.INIT, # type: ignore
161
+ transaction_open=False,
162
+ handle=None,
163
+ credentials=self.profile.credentials,
164
+ )
165
+ conn.handle = LazyHandle(self.open)
166
+ # Add the connection to thread_connections for this thread
167
+ self.set_thread_connection(conn)
168
+ fire_event(
169
+ NewConnection(conn_name=conn_name, conn_type=self.TYPE, node_info=get_node_info())
170
+ )
171
+ else: # existing connection either wasn't open or didn't have the right name
172
+ if conn.state != "open":
173
+ conn.handle = LazyHandle(self.open)
174
+ if conn.name != conn_name:
175
+ orig_conn_name: str = conn.name or ""
176
+ conn.name = conn_name
177
+ fire_event(ConnectionReused(orig_conn_name=orig_conn_name, conn_name=conn_name))
178
+
179
+ return conn
180
+
181
+ @classmethod
182
+ def retry_connection(
183
+ cls,
184
+ connection: Connection,
185
+ connect: Callable[[], AdapterHandle],
186
+ logger: AdapterLogger,
187
+ retryable_exceptions: Iterable[Type[Exception]],
188
+ retry_limit: int = 1,
189
+ retry_timeout: Union[Callable[[int], SleepTime], SleepTime] = 1,
190
+ _attempts: int = 0,
191
+ ) -> Connection:
192
+ """Given a Connection, set its handle by calling connect.
193
+
194
+ The calls to connect will be retried up to retry_limit times to deal with transient
195
+ connection errors. By default, one retry will be attempted if retryable_exceptions is set.
196
+
197
+ :param Connection connection: An instance of a Connection that needs a handle to be set,
198
+ usually when attempting to open it.
199
+ :param connect: A callable that returns the appropiate connection handle for a
200
+ given adapter. This callable will be retried retry_limit times if a subclass of any
201
+ Exception in retryable_exceptions is raised by connect.
202
+ :type connect: Callable[[], AdapterHandle]
203
+ :param AdapterLogger logger: A logger to emit messages on retry attempts or errors. When
204
+ handling expected errors, we call debug, and call warning on unexpected errors or when
205
+ all retry attempts have been exhausted.
206
+ :param retryable_exceptions: An iterable of exception classes that if raised by
207
+ connect should trigger a retry.
208
+ :type retryable_exceptions: Iterable[Type[Exception]]
209
+ :param int retry_limit: How many times to retry the call to connect. If this limit
210
+ is exceeded before a successful call, a FailedToConnectError will be raised.
211
+ Must be non-negative.
212
+ :param retry_timeout: Time to wait between attempts to connect. Can also take a
213
+ Callable that takes the number of attempts so far, beginning at 0, and returns an int
214
+ or float to be passed to time.sleep.
215
+ :type retry_timeout: Union[Callable[[int], SleepTime], SleepTime] = 1
216
+ :param int _attempts: Parameter used to keep track of the number of attempts in calling the
217
+ connect function across recursive calls. Passed as an argument to retry_timeout if it
218
+ is a Callable. This parameter should not be set by the initial caller.
219
+ :raises dbt.adapters.exceptions.FailedToConnectError: Upon exhausting all retry attempts without
220
+ successfully acquiring a handle.
221
+ :return: The given connection with its appropriate state and handle attributes set
222
+ depending on whether we successfully acquired a handle or not.
223
+ """
224
+ timeout = retry_timeout(_attempts) if callable(retry_timeout) else retry_timeout
225
+ if timeout < 0:
226
+ raise FailedToConnectError(
227
+ "retry_timeout cannot be negative or return a negative time."
228
+ )
229
+
230
+ if retry_limit < 0 or retry_limit > sys.getrecursionlimit():
231
+ # This guard is not perfect others may add to the recursion limit (e.g. built-ins).
232
+ connection.handle = None
233
+ connection.state = ConnectionState.FAIL # type: ignore
234
+ raise FailedToConnectError("retry_limit cannot be negative")
235
+
236
+ try:
237
+ connection.handle = connect()
238
+ connection.state = ConnectionState.OPEN # type: ignore
239
+ return connection
240
+
241
+ except tuple(retryable_exceptions) as e:
242
+ if retry_limit <= 0:
243
+ connection.handle = None
244
+ connection.state = ConnectionState.FAIL # type: ignore
245
+ raise FailedToConnectError(str(e))
246
+
247
+ logger.debug(
248
+ f"Got a retryable error when attempting to open a {cls.TYPE} connection.\n"
249
+ f"{retry_limit} attempts remaining. Retrying in {timeout} seconds.\n"
250
+ f"Error:\n{e}"
251
+ )
252
+
253
+ sleep(timeout)
254
+ return cls.retry_connection(
255
+ connection=connection,
256
+ connect=connect,
257
+ logger=logger,
258
+ retry_limit=retry_limit - 1,
259
+ retry_timeout=retry_timeout,
260
+ retryable_exceptions=retryable_exceptions,
261
+ _attempts=_attempts + 1,
262
+ )
263
+
264
+ except Exception as e:
265
+ connection.handle = None
266
+ connection.state = ConnectionState.FAIL # type: ignore
267
+ raise FailedToConnectError(str(e))
268
+
269
+ @abc.abstractmethod
270
+ def cancel_open(self) -> Optional[List[str]]:
271
+ """Cancel all open connections on the adapter. (passable)"""
272
+ raise NotImplementedError("`cancel_open` is not implemented for this adapter!")
273
+
274
+ @classmethod
275
+ @abc.abstractmethod
276
+ def open(cls, connection: Connection) -> Connection:
277
+ """Open the given connection on the adapter and return it.
278
+
279
+ This may mutate the given connection (in particular, its state and its
280
+ handle).
281
+
282
+ This should be thread-safe, or hold the lock if necessary. The given
283
+ connection should not be in either in_use or available.
284
+ """
285
+ raise NotImplementedError("`open` is not implemented for this adapter!")
286
+
287
+ def release(self) -> None:
288
+ with self.lock:
289
+ conn = self.get_if_exists()
290
+ if conn is None:
291
+ return
292
+
293
+ try:
294
+ # always close the connection. close() calls _rollback() if there
295
+ # is an open transaction
296
+ self.close(conn)
297
+ except Exception:
298
+ # if rollback or close failed, remove our busted connection
299
+ self.clear_thread_connection()
300
+ raise
301
+
302
+ def cleanup_all(self) -> None:
303
+ with self.lock:
304
+ for connection in self.thread_connections.values():
305
+ if connection.state not in {"closed", "init"}:
306
+ fire_event(ConnectionLeftOpenInCleanup(conn_name=cast_to_str(connection.name)))
307
+ else:
308
+ fire_event(ConnectionClosedInCleanup(conn_name=cast_to_str(connection.name)))
309
+ self.close(connection)
310
+
311
+ # garbage collect these connections
312
+ self.thread_connections.clear()
313
+
314
+ @abc.abstractmethod
315
+ def begin(self) -> None:
316
+ """Begin a transaction. (passable)"""
317
+ raise NotImplementedError("`begin` is not implemented for this adapter!")
318
+
319
+ @abc.abstractmethod
320
+ def commit(self) -> None:
321
+ """Commit a transaction. (passable)"""
322
+ raise NotImplementedError("`commit` is not implemented for this adapter!")
323
+
324
+ @classmethod
325
+ def _rollback_handle(cls, connection: Connection) -> None:
326
+ """Perform the actual rollback operation."""
327
+ try:
328
+ connection.handle.rollback()
329
+ except Exception:
330
+ fire_event(
331
+ RollbackFailed(
332
+ conn_name=cast_to_str(connection.name),
333
+ exc_info=traceback.format_exc(),
334
+ node_info=get_node_info(),
335
+ )
336
+ )
337
+
338
+ @classmethod
339
+ def _close_handle(cls, connection: Connection) -> None:
340
+ """Perform the actual close operation."""
341
+ # On windows, sometimes connection handles don't have a close() attr.
342
+ if hasattr(connection.handle, "close"):
343
+ fire_event(
344
+ ConnectionClosed(conn_name=cast_to_str(connection.name), node_info=get_node_info())
345
+ )
346
+ connection.handle.close()
347
+ else:
348
+ fire_event(
349
+ ConnectionLeftOpen(
350
+ conn_name=cast_to_str(connection.name), node_info=get_node_info()
351
+ )
352
+ )
353
+
354
+ @classmethod
355
+ def _rollback(cls, connection: Connection) -> None:
356
+ """Roll back the given connection."""
357
+ if connection.transaction_open is False:
358
+ raise DbtInternalError(
359
+ f"Tried to rollback transaction on connection "
360
+ f'"{connection.name}", but it does not have one open!'
361
+ )
362
+
363
+ fire_event(Rollback(conn_name=cast_to_str(connection.name), node_info=get_node_info()))
364
+ cls._rollback_handle(connection)
365
+
366
+ connection.transaction_open = False
367
+
368
+ @classmethod
369
+ def close(cls, connection: Connection) -> Connection:
370
+ # if the connection is in closed or init, there's nothing to do
371
+ if connection.state in {ConnectionState.CLOSED, ConnectionState.INIT}:
372
+ return connection
373
+
374
+ if connection.transaction_open and connection.handle:
375
+ fire_event(Rollback(conn_name=cast_to_str(connection.name), node_info=get_node_info()))
376
+ cls._rollback_handle(connection)
377
+ connection.transaction_open = False
378
+
379
+ cls._close_handle(connection)
380
+ connection.state = ConnectionState.CLOSED # type: ignore
381
+
382
+ return connection
383
+
384
+ def commit_if_has_connection(self) -> None:
385
+ """If the named connection exists, commit the current transaction."""
386
+ connection = self.get_if_exists()
387
+ if connection:
388
+ self.commit()
389
+
390
+ def _add_query_comment(self, sql: str) -> str:
391
+ if self.query_header is None:
392
+ return sql
393
+ return self.query_header.add(sql)
394
+
395
+ @abc.abstractmethod
396
+ def execute(
397
+ self,
398
+ sql: str,
399
+ auto_begin: bool = False,
400
+ fetch: bool = False,
401
+ limit: Optional[int] = None,
402
+ ) -> Tuple[AdapterResponse, "agate.Table"]:
403
+ """Execute the given SQL.
404
+
405
+ :param str sql: The sql to execute.
406
+ :param bool auto_begin: If set, and dbt is not currently inside a
407
+ transaction, automatically begin one.
408
+ :param bool fetch: If set, fetch results.
409
+ :param int limit: If set, limits the result set
410
+ :return: A tuple of the query status and results (empty if fetch=False).
411
+ :rtype: Tuple[AdapterResponse, agate.Table]
412
+ """
413
+ raise NotImplementedError("`execute` is not implemented for this adapter!")
414
+
415
+ def add_select_query(self, sql: str) -> Tuple[Connection, Any]:
416
+ """
417
+ This was added here because base.impl.BaseAdapter.get_column_schema_from_query expects it to be here.
418
+ That method wouldn't work unless the adapter used sql.impl.SQLAdapter, sql.connections.SQLConnectionManager
419
+ or defined this method on <Adapter>ConnectionManager before passing it in to <Adapter>Adapter.
420
+
421
+ See https://github.com/dbt-labs/dbt-core/issues/8396 for more information.
422
+ """
423
+ raise NotImplementedError("`add_select_query` is not implemented for this adapter!")
424
+
425
+ @classmethod
426
+ def data_type_code_to_name(cls, type_code: Union[int, str]) -> str:
427
+ """Get the string representation of the data type from the type_code."""
428
+ # https://peps.python.org/pep-0249/#type-objects
429
+ raise NotImplementedError("`data_type_code_to_name` is not implemented for this adapter!")