dbt-sqlserver 1.8.7__tar.gz → 1.9.1__tar.gz

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 (84) hide show
  1. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/PKG-INFO +44 -7
  2. dbt-sqlserver-1.8.7/dbt_sqlserver.egg-info/PKG-INFO → dbt_sqlserver-1.9.1/README.md +27 -28
  3. dbt_sqlserver-1.9.1/dbt/__init__.py +3 -0
  4. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/adapters/sqlserver/__init__.py +1 -2
  5. dbt_sqlserver-1.9.1/dbt/adapters/sqlserver/__version__.py +1 -0
  6. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/adapters/sqlserver/relation_configs/policies.py +2 -1
  7. dbt_sqlserver-1.9.1/dbt/adapters/sqlserver/sqlserver_adapter.py +290 -0
  8. dbt_sqlserver-1.9.1/dbt/adapters/sqlserver/sqlserver_column.py +99 -0
  9. dbt_sqlserver-1.9.1/dbt/adapters/sqlserver/sqlserver_configs.py +9 -0
  10. dbt_sqlserver-1.9.1/dbt/adapters/sqlserver/sqlserver_connections.py +673 -0
  11. dbt_sqlserver-1.9.1/dbt/adapters/sqlserver/sqlserver_credentials.py +74 -0
  12. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/adapters/sqlserver/sqlserver_relation.py +29 -4
  13. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/dbt_project.yml +1 -1
  14. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters/apply_grants.sql +71 -0
  15. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters/columns.sql +101 -0
  16. {dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/adapter → dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters}/indexes.sql +68 -0
  17. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters/metadata.sql +112 -0
  18. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters/relation.sql +55 -0
  19. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters/schema.sql +70 -0
  20. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters/show.sql +12 -0
  21. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/models/incremental/incremental_strategies.sql +11 -0
  22. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/models/incremental/merge.sql +85 -0
  23. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/models/table/clone.sql +4 -0
  24. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/models/table/columns_spec_ddl.sql +30 -0
  25. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/models/unit_test/unit_test_create_table_as.sql +58 -0
  26. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/models/view/create_view_as.sql +12 -0
  27. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/snapshots/helpers.sql +189 -0
  28. {dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/materializations/snapshot → dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/snapshots}/snapshot.sql +33 -34
  29. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/snapshots/snapshot_merge.sql +30 -0
  30. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/snapshots/strategies.sql +5 -0
  31. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/materializations/unit_tests.sql +47 -0
  32. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/any_value.sql +5 -0
  33. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/array_construct.sql +3 -0
  34. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/cast_bool_to_text.sql +7 -0
  35. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/concat.sql +7 -0
  36. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/date_trunc.sql +3 -0
  37. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/dateadd.sql +9 -0
  38. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/get_tables_by_pattern.sql +12 -0
  39. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/hash.sql +3 -0
  40. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/last_day.sql +13 -0
  41. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/length.sql +5 -0
  42. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/listagg.sql +8 -0
  43. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/position.sql +8 -0
  44. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/safe_cast.sql +3 -0
  45. dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/utils/timestamps.sql +8 -0
  46. dbt-sqlserver-1.8.7/README.md → dbt_sqlserver-1.9.1/dbt_sqlserver.egg-info/PKG-INFO +65 -0
  47. dbt_sqlserver-1.9.1/dbt_sqlserver.egg-info/SOURCES.txt +66 -0
  48. dbt_sqlserver-1.9.1/dbt_sqlserver.egg-info/requires.txt +4 -0
  49. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/setup.py +5 -6
  50. dbt-sqlserver-1.8.7/dbt/adapters/sqlserver/__version__.py +0 -1
  51. dbt-sqlserver-1.8.7/dbt/adapters/sqlserver/sqlserver_adapter.py +0 -61
  52. dbt-sqlserver-1.8.7/dbt/adapters/sqlserver/sqlserver_column.py +0 -22
  53. dbt-sqlserver-1.8.7/dbt/adapters/sqlserver/sqlserver_configs.py +0 -8
  54. dbt-sqlserver-1.8.7/dbt/adapters/sqlserver/sqlserver_connections.py +0 -160
  55. dbt-sqlserver-1.8.7/dbt/adapters/sqlserver/sqlserver_credentials.py +0 -22
  56. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/adapter/columns.sql +0 -25
  57. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/adapter/metadata.sql +0 -8
  58. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/adapter/relation.sql +0 -5
  59. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/adapter/schemas.sql +0 -5
  60. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/materializations/snapshot/helpers.sql +0 -35
  61. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/materializations/snapshot/snapshot_merge.sql +0 -19
  62. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/materializations/unit_tests.sql +0 -47
  63. dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/readme.md +0 -54
  64. dbt-sqlserver-1.8.7/dbt_sqlserver.egg-info/SOURCES.txt +0 -43
  65. dbt-sqlserver-1.8.7/dbt_sqlserver.egg-info/requires.txt +0 -4
  66. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/LICENSE +0 -0
  67. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/MANIFEST.in +0 -0
  68. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/adapters/sqlserver/relation_configs/__init__.py +0 -0
  69. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/__init__.py +0 -0
  70. {dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/adapter → dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters}/catalog.sql +0 -0
  71. {dbt-sqlserver-1.8.7/dbt/include/sqlserver/macros/adapter → dbt_sqlserver-1.9.1/dbt/include/sqlserver/macros/adapters}/validate_sql.sql +0 -0
  72. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/materializations/models/incremental/incremental.sql +0 -0
  73. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/materializations/models/table/table.sql +0 -0
  74. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/materializations/models/view/view.sql +0 -0
  75. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/materializations/tests.sql +0 -0
  76. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/relations/seeds/helpers.sql +0 -0
  77. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/relations/table/clone.sql +0 -0
  78. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/relations/table/create.sql +0 -0
  79. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/relations/views/create.sql +0 -0
  80. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/macros/utils/split_part.sql +0 -0
  81. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt/include/sqlserver/profile_template.yml +0 -0
  82. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt_sqlserver.egg-info/dependency_links.txt +0 -0
  83. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/dbt_sqlserver.egg-info/top_level.txt +0 -0
  84. {dbt-sqlserver-1.8.7 → dbt_sqlserver-1.9.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: dbt-sqlserver
3
- Version: 1.8.7
3
+ Version: 1.9.1
4
4
  Summary: A Microsoft SQL Server adapter plugin for dbt
5
5
  Home-page: https://github.com/dbt-msft/dbt-sqlserver
6
6
  Author: Mikael Ene, Anders Swanson, Sam Debruyn, Cor Zuurmond, Cody Scott
@@ -9,20 +9,32 @@ Project-URL: Setup & configuration, https://docs.getdbt.com/reference/warehouse-
9
9
  Project-URL: Documentation & usage, https://docs.getdbt.com/reference/resource-configs/mssql-configs
10
10
  Project-URL: Changelog, https://github.com/dbt-msft/dbt-sqlserver/blob/master/CHANGELOG.md
11
11
  Project-URL: Issue Tracker, https://github.com/dbt-msft/dbt-sqlserver/issues
12
- Platform: UNKNOWN
13
12
  Classifier: Development Status :: 5 - Production/Stable
14
13
  Classifier: License :: OSI Approved :: MIT License
15
14
  Classifier: Operating System :: Microsoft :: Windows
16
15
  Classifier: Operating System :: MacOS :: MacOS X
17
16
  Classifier: Operating System :: POSIX :: Linux
18
- Classifier: Programming Language :: Python :: 3.7
19
- Classifier: Programming Language :: Python :: 3.8
20
17
  Classifier: Programming Language :: Python :: 3.9
21
18
  Classifier: Programming Language :: Python :: 3.10
22
19
  Classifier: Programming Language :: Python :: 3.11
23
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
24
22
  Description-Content-Type: text/markdown
25
23
  License-File: LICENSE
24
+ Requires-Dist: dbt-core<2.0,>=1.9.0
25
+ Requires-Dist: dbt-common<2.0,>=1.0
26
+ Requires-Dist: dbt-adapters<2.0,>=1.11.0
27
+ Requires-Dist: pyodbc>=5.2.0
28
+ Dynamic: author
29
+ Dynamic: classifier
30
+ Dynamic: description
31
+ Dynamic: description-content-type
32
+ Dynamic: home-page
33
+ Dynamic: license
34
+ Dynamic: license-file
35
+ Dynamic: project-url
36
+ Dynamic: requires-dist
37
+ Dynamic: summary
26
38
 
27
39
  # dbt-sqlserver
28
40
 
@@ -75,6 +87,33 @@ pip install -U --pre dbt-sqlserver
75
87
 
76
88
  See [the changelog](CHANGELOG.md)
77
89
 
90
+ ## Configuration
91
+
92
+ ### Flags
93
+
94
+ - `dbt_sqlserver_use_default_schema_concat`: *(default: `false`)* Controls schema name generation when a [custom schema](https://docs.getdbt.com/docs/build/custom-schemas) is set on a model.
95
+
96
+ | Flag value | `custom_schema_name` | Result |
97
+ |---|---|---|
98
+ | `false` (default, legacy) | *(none)* | `target.schema` |
99
+ | `false` (default, legacy) | `"reporting"` | `reporting` |
100
+ | `true` (dbt-core standard) | *(none)* | `target.schema` |
101
+ | `true` (dbt-core standard) | `"reporting"` | `target.schema_reporting` |
102
+
103
+ When `false` (the default), the adapter uses its legacy behaviour: `custom_schema_name` is used **as-is** without being prefixed by `target.schema`.
104
+ When `true`, the adapter delegates to dbt-core's `default__generate_schema_name`, which concatenates `target.schema` + `_` + `custom_schema_name`.
105
+
106
+ **Example usage in `dbt_project.yml`:**
107
+
108
+ ```yaml
109
+ vars:
110
+ dbt_sqlserver_use_default_schema_concat: true # Enable standard schema concatenation
111
+ ```
112
+
113
+ > **Note:** If you want to permanently customise schema generation and avoid any future deprecation of this flag, override the `sqlserver__generate_schema_name` macro directly in your project.
114
+
115
+
116
+
78
117
  ## Contributing
79
118
 
80
119
  [![Unit tests](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/unit-tests.yml)
@@ -92,5 +131,3 @@ If you're unsure how to get started, check out our [contributing guide](CONTRIBU
92
131
  ## Code of Conduct
93
132
 
94
133
  This project and everyone involved is expected to follow the [dbt Code of Conduct](https://community.getdbt.com/code-of-conduct).
95
-
96
-
@@ -1,29 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: dbt-sqlserver
3
- Version: 1.8.7
4
- Summary: A Microsoft SQL Server adapter plugin for dbt
5
- Home-page: https://github.com/dbt-msft/dbt-sqlserver
6
- Author: Mikael Ene, Anders Swanson, Sam Debruyn, Cor Zuurmond, Cody Scott
7
- License: MIT
8
- Project-URL: Setup & configuration, https://docs.getdbt.com/reference/warehouse-profiles/mssql-profile
9
- Project-URL: Documentation & usage, https://docs.getdbt.com/reference/resource-configs/mssql-configs
10
- Project-URL: Changelog, https://github.com/dbt-msft/dbt-sqlserver/blob/master/CHANGELOG.md
11
- Project-URL: Issue Tracker, https://github.com/dbt-msft/dbt-sqlserver/issues
12
- Platform: UNKNOWN
13
- Classifier: Development Status :: 5 - Production/Stable
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Operating System :: Microsoft :: Windows
16
- Classifier: Operating System :: MacOS :: MacOS X
17
- Classifier: Operating System :: POSIX :: Linux
18
- Classifier: Programming Language :: Python :: 3.7
19
- Classifier: Programming Language :: Python :: 3.8
20
- Classifier: Programming Language :: Python :: 3.9
21
- Classifier: Programming Language :: Python :: 3.10
22
- Classifier: Programming Language :: Python :: 3.11
23
- Classifier: Programming Language :: Python :: 3.12
24
- Description-Content-Type: text/markdown
25
- License-File: LICENSE
26
-
27
1
  # dbt-sqlserver
28
2
 
29
3
  [dbt](https://www.getdbt.com) adapter for Microsoft SQL Server and Azure SQL services.
@@ -75,6 +49,33 @@ pip install -U --pre dbt-sqlserver
75
49
 
76
50
  See [the changelog](CHANGELOG.md)
77
51
 
52
+ ## Configuration
53
+
54
+ ### Flags
55
+
56
+ - `dbt_sqlserver_use_default_schema_concat`: *(default: `false`)* Controls schema name generation when a [custom schema](https://docs.getdbt.com/docs/build/custom-schemas) is set on a model.
57
+
58
+ | Flag value | `custom_schema_name` | Result |
59
+ |---|---|---|
60
+ | `false` (default, legacy) | *(none)* | `target.schema` |
61
+ | `false` (default, legacy) | `"reporting"` | `reporting` |
62
+ | `true` (dbt-core standard) | *(none)* | `target.schema` |
63
+ | `true` (dbt-core standard) | `"reporting"` | `target.schema_reporting` |
64
+
65
+ When `false` (the default), the adapter uses its legacy behaviour: `custom_schema_name` is used **as-is** without being prefixed by `target.schema`.
66
+ When `true`, the adapter delegates to dbt-core's `default__generate_schema_name`, which concatenates `target.schema` + `_` + `custom_schema_name`.
67
+
68
+ **Example usage in `dbt_project.yml`:**
69
+
70
+ ```yaml
71
+ vars:
72
+ dbt_sqlserver_use_default_schema_concat: true # Enable standard schema concatenation
73
+ ```
74
+
75
+ > **Note:** If you want to permanently customise schema generation and avoid any future deprecation of this flag, override the `sqlserver__generate_schema_name` macro directly in your project.
76
+
77
+
78
+
78
79
  ## Contributing
79
80
 
80
81
  [![Unit tests](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/unit-tests.yml)
@@ -92,5 +93,3 @@ If you're unsure how to get started, check out our [contributing guide](CONTRIBU
92
93
  ## Code of Conduct
93
94
 
94
95
  This project and everyone involved is expected to follow the [dbt Code of Conduct](https://community.getdbt.com/code-of-conduct).
95
-
96
-
@@ -0,0 +1,3 @@
1
+ from pkgutil import extend_path
2
+
3
+ __path__ = extend_path(__path__, __name__)
@@ -1,5 +1,4 @@
1
1
  from dbt.adapters.base import AdapterPlugin
2
-
3
2
  from dbt.adapters.sqlserver.sqlserver_adapter import SQLServerAdapter
4
3
  from dbt.adapters.sqlserver.sqlserver_column import SQLServerColumn
5
4
  from dbt.adapters.sqlserver.sqlserver_configs import SQLServerConfigs
@@ -11,7 +10,7 @@ Plugin = AdapterPlugin(
11
10
  adapter=SQLServerAdapter,
12
11
  credentials=SQLServerCredentials,
13
12
  include_path=sqlserver.PACKAGE_PATH,
14
- dependencies=["fabric"],
13
+ dependencies=[],
15
14
  )
16
15
 
17
16
  __all__ = [
@@ -0,0 +1 @@
1
+ version = "1.9.1"
@@ -1,8 +1,9 @@
1
1
  from dataclasses import dataclass
2
2
 
3
- from dbt.adapters.contracts.relation import Policy
4
3
  from dbt_common.dataclass_schema import StrEnum
5
4
 
5
+ from dbt.adapters.contracts.relation import Policy
6
+
6
7
  MAX_CHARACTERS_IN_IDENTIFIER = 127
7
8
 
8
9
 
@@ -0,0 +1,290 @@
1
+ from typing import List, Optional
2
+
3
+ import agate
4
+ import dbt_common.exceptions
5
+ from dbt_common.behavior_flags import BehaviorFlag
6
+ from dbt_common.contracts.constraints import (
7
+ ColumnLevelConstraint,
8
+ ConstraintType,
9
+ ModelLevelConstraint,
10
+ )
11
+ from dbt_common.events.functions import fire_event
12
+
13
+ from dbt.adapters.base.column import Column as BaseColumn
14
+ from dbt.adapters.base.impl import ConstraintSupport
15
+ from dbt.adapters.base.meta import available
16
+ from dbt.adapters.base.relation import BaseRelation
17
+ from dbt.adapters.capability import Capability, CapabilityDict, CapabilitySupport, Support
18
+ from dbt.adapters.events.types import SchemaCreation
19
+ from dbt.adapters.reference_keys import _make_ref_key_dict
20
+ from dbt.adapters.sql.impl import CREATE_SCHEMA_MACRO_NAME, SQLAdapter
21
+ from dbt.adapters.sqlserver.sqlserver_column import SQLServerColumn
22
+ from dbt.adapters.sqlserver.sqlserver_configs import SQLServerConfigs
23
+ from dbt.adapters.sqlserver.sqlserver_connections import SQLServerConnectionManager
24
+ from dbt.adapters.sqlserver.sqlserver_relation import SQLServerRelation
25
+
26
+
27
+ class SQLServerAdapter(SQLAdapter):
28
+ """
29
+ Controls actual implmentation of adapter, and ability to override certain methods.
30
+ """
31
+
32
+ ConnectionManager = SQLServerConnectionManager
33
+ Column = SQLServerColumn
34
+ AdapterSpecificConfigs = SQLServerConfigs
35
+ Relation = SQLServerRelation
36
+
37
+ _capabilities: CapabilityDict = CapabilityDict(
38
+ {
39
+ Capability.SchemaMetadataByRelations: CapabilitySupport(support=Support.Full),
40
+ Capability.TableLastModifiedMetadata: CapabilitySupport(support=Support.Full),
41
+ }
42
+ )
43
+ CONSTRAINT_SUPPORT = {
44
+ ConstraintType.check: ConstraintSupport.ENFORCED,
45
+ ConstraintType.not_null: ConstraintSupport.ENFORCED,
46
+ ConstraintType.unique: ConstraintSupport.ENFORCED,
47
+ ConstraintType.primary_key: ConstraintSupport.ENFORCED,
48
+ ConstraintType.foreign_key: ConstraintSupport.ENFORCED,
49
+ }
50
+
51
+ @property
52
+ def _behavior_flags(self) -> List[BehaviorFlag]:
53
+ return [
54
+ {
55
+ "name": "empty",
56
+ "default": False,
57
+ "description": (
58
+ "When enabled, table and view materializations will be created as empty "
59
+ "structures (no data)."
60
+ ),
61
+ },
62
+ {
63
+ "name": "dbt_sqlserver_use_default_schema_concat",
64
+ "default": False,
65
+ "description": (
66
+ "When True, uses dbt-core's standard schema concatenation "
67
+ "(`target.schema` + `_` + `custom_schema_name`). "
68
+ "When False (default), uses legacy adapter behaviour: "
69
+ "`custom_schema_name` is used directly without prefixing `target.schema`. "
70
+ "For a permanent solution, override the `sqlserver__generate_schema_name` "
71
+ "macro in your project instead."
72
+ ),
73
+ },
74
+ ]
75
+
76
+ @available.parse(lambda *a, **k: [])
77
+ def get_column_schema_from_query(self, sql: str) -> List[BaseColumn]:
78
+ """Get a list of the Columns with names and data types from the given sql."""
79
+ _, cursor = self.connections.add_select_query(sql)
80
+
81
+ columns = [
82
+ self.Column.create(
83
+ column_name, self.connections.data_type_code_to_name(column_type_code)
84
+ )
85
+ # https://peps.python.org/pep-0249/#description
86
+ for column_name, column_type_code, *_ in cursor.description
87
+ ]
88
+ return columns
89
+
90
+ @classmethod
91
+ def convert_boolean_type(cls, agate_table, col_idx):
92
+ return "bit"
93
+
94
+ @classmethod
95
+ def convert_datetime_type(cls, agate_table, col_idx):
96
+ return "datetime2(6)"
97
+
98
+ @classmethod
99
+ def convert_number_type(cls, agate_table, col_idx):
100
+ decimals = agate_table.aggregate(agate.MaxPrecision(col_idx))
101
+ return "float" if decimals else "int"
102
+
103
+ def create_schema(self, relation: BaseRelation) -> None:
104
+ relation = relation.without_identifier()
105
+ fire_event(SchemaCreation(relation=_make_ref_key_dict(relation)))
106
+ macro_name = CREATE_SCHEMA_MACRO_NAME
107
+ kwargs = {
108
+ "relation": relation,
109
+ }
110
+
111
+ if self.config.credentials.schema_authorization:
112
+ kwargs["schema_authorization"] = self.config.credentials.schema_authorization
113
+ macro_name = "sqlserver__create_schema_with_authorization"
114
+
115
+ self.execute_macro(macro_name, kwargs=kwargs)
116
+ self.commit_if_has_connection()
117
+
118
+ @classmethod
119
+ def convert_text_type(cls, agate_table, col_idx):
120
+ column = agate_table.columns[col_idx]
121
+ # see https://github.com/fishtown-analytics/dbt/pull/2255
122
+ lens = [len(d.encode("utf-8")) for d in column.values_without_nulls()]
123
+ max_len = max(lens) if lens else 64
124
+ length = max_len if max_len > 16 else 16
125
+ return "varchar({})".format(length)
126
+
127
+ @classmethod
128
+ def convert_time_type(cls, agate_table, col_idx):
129
+ return "time(6)"
130
+
131
+ @classmethod
132
+ def date_function(cls):
133
+ return "getdate()"
134
+
135
+ # Methods used in adapter tests
136
+ def timestamp_add_sql(self, add_to: str, number: int = 1, interval: str = "hour") -> str:
137
+ # note: 'interval' is not supported for T-SQL
138
+ # for backwards compatibility, we're compelled to set some sort of
139
+ # default. A lot of searching has lead me to believe that the
140
+ # '+ interval' syntax used in postgres/redshift is relatively common
141
+ # and might even be the SQL standard's intention.
142
+ return f"DATEADD({interval},{number},{add_to})"
143
+
144
+ def string_add_sql(
145
+ self,
146
+ add_to: str,
147
+ value: str,
148
+ location="append",
149
+ ) -> str:
150
+ """
151
+ `+` is T-SQL's string concatenation operator
152
+ """
153
+ if location == "append":
154
+ return f"{add_to} + '{value}'"
155
+ elif location == "prepend":
156
+ return f"'{value}' + {add_to}"
157
+ else:
158
+ raise ValueError(f'Got an unexpected location value of "{location}"')
159
+
160
+ def get_rows_different_sql(
161
+ self,
162
+ relation_a: BaseRelation,
163
+ relation_b: BaseRelation,
164
+ column_names: Optional[List[str]] = None,
165
+ except_operator: str = "EXCEPT",
166
+ ) -> str:
167
+ """
168
+ note: using is not supported on Synapse so COLUMNS_EQUAL_SQL is adjsuted
169
+ Generate SQL for a query that returns a single row with a two
170
+ columns: the number of rows that are different between the two
171
+ relations and the number of mismatched rows.
172
+ """
173
+ # This method only really exists for test reasons.
174
+ names: List[str]
175
+ if column_names is None:
176
+ columns = self.get_columns_in_relation(relation_a)
177
+ names = sorted((self.quote(c.name) for c in columns))
178
+ else:
179
+ names = sorted((self.quote(n) for n in column_names))
180
+ columns_csv = ", ".join(names)
181
+
182
+ if columns_csv == "":
183
+ columns_csv = "*"
184
+
185
+ sql = COLUMNS_EQUAL_SQL.format(
186
+ columns=columns_csv,
187
+ relation_a=str(relation_a),
188
+ relation_b=str(relation_b),
189
+ except_op=except_operator,
190
+ )
191
+
192
+ return sql
193
+
194
+ def valid_incremental_strategies(self):
195
+ """The set of standard builtin strategies which this adapter supports out-of-the-box.
196
+ Not used to validate custom strategies defined by end users.
197
+ """
198
+ return ["append", "delete+insert", "merge", "microbatch"]
199
+
200
+ # This is for use in the test suite
201
+ def run_sql_for_tests(self, sql, fetch, conn):
202
+ cursor = conn.handle.cursor()
203
+ try:
204
+ cursor.execute(sql)
205
+ if not fetch:
206
+ conn.handle.commit()
207
+ if fetch == "one":
208
+ return cursor.fetchone()
209
+ elif fetch == "all":
210
+ return cursor.fetchall()
211
+ else:
212
+ return
213
+ except BaseException:
214
+ if conn.handle and not getattr(conn.handle, "closed", True):
215
+ conn.handle.rollback()
216
+ raise
217
+ finally:
218
+ conn.transaction_open = False
219
+
220
+ @available
221
+ @classmethod
222
+ def render_column_constraint(cls, constraint: ColumnLevelConstraint) -> Optional[str]:
223
+ rendered_column_constraint = None
224
+ if constraint.type == ConstraintType.not_null:
225
+ rendered_column_constraint = "not null "
226
+ else:
227
+ rendered_column_constraint = ""
228
+
229
+ if rendered_column_constraint:
230
+ rendered_column_constraint = rendered_column_constraint.strip()
231
+
232
+ return rendered_column_constraint
233
+
234
+ @classmethod
235
+ def render_model_constraint(cls, constraint: ModelLevelConstraint) -> Optional[str]:
236
+ constraint_prefix = "add constraint "
237
+ column_list = ", ".join(constraint.columns)
238
+
239
+ if constraint.name is None:
240
+ raise dbt_common.exceptions.DbtDatabaseError(
241
+ "Constraint name cannot be empty. Provide constraint name - column "
242
+ + column_list
243
+ + " and run the project again."
244
+ )
245
+
246
+ if constraint.type == ConstraintType.unique:
247
+ return constraint_prefix + f"{constraint.name} unique nonclustered({column_list})"
248
+ elif constraint.type == ConstraintType.primary_key:
249
+ return constraint_prefix + f"{constraint.name} primary key nonclustered({column_list})"
250
+ elif constraint.type == ConstraintType.foreign_key and constraint.expression:
251
+ return (
252
+ constraint_prefix
253
+ + f"{constraint.name} foreign key({column_list}) references "
254
+ + constraint.expression
255
+ )
256
+ elif constraint.type == ConstraintType.check and constraint.expression:
257
+ return f"{constraint_prefix} {constraint.name} check ({constraint.expression})"
258
+ elif constraint.type == ConstraintType.custom and constraint.expression:
259
+ return f"{constraint_prefix} {constraint.name} {constraint.expression}"
260
+ else:
261
+ return None
262
+
263
+
264
+ COLUMNS_EQUAL_SQL = """
265
+ with diff_count as (
266
+ SELECT
267
+ 1 as id,
268
+ COUNT(*) as num_missing FROM (
269
+ (SELECT {columns} FROM {relation_a} {except_op}
270
+ SELECT {columns} FROM {relation_b})
271
+ UNION ALL
272
+ (SELECT {columns} FROM {relation_b} {except_op}
273
+ SELECT {columns} FROM {relation_a})
274
+ ) as a
275
+ ), table_a as (
276
+ SELECT COUNT(*) as num_rows FROM {relation_a}
277
+ ), table_b as (
278
+ SELECT COUNT(*) as num_rows FROM {relation_b}
279
+ ), row_count_diff as (
280
+ select
281
+ 1 as id,
282
+ table_a.num_rows - table_b.num_rows as difference
283
+ from table_a, table_b
284
+ )
285
+ select
286
+ row_count_diff.difference as row_count_difference,
287
+ diff_count.num_missing as num_mismatched
288
+ from row_count_diff
289
+ join diff_count on row_count_diff.id = diff_count.id
290
+ """.strip()
@@ -0,0 +1,99 @@
1
+ from typing import Any, ClassVar, Dict
2
+
3
+ from dbt_common.exceptions import DbtRuntimeError
4
+
5
+ from dbt.adapters.base.column import Column
6
+
7
+
8
+ class SQLServerColumn(Column):
9
+ TYPE_LABELS: ClassVar[Dict[str, str]] = {
10
+ "STRING": "VARCHAR(8000)",
11
+ "VARCHAR": "VARCHAR(8000)",
12
+ "CHAR": "CHAR(1)",
13
+ "NCHAR": "CHAR(1)",
14
+ "NVARCHAR": "VARCHAR(8000)",
15
+ "TIMESTAMP": "DATETIME2(6)",
16
+ "DATETIME2": "DATETIME2(6)",
17
+ "DATETIME2(6)": "DATETIME2(6)",
18
+ "DATE": "DATE",
19
+ "TIME": "TIME(6)",
20
+ "FLOAT": "FLOAT",
21
+ "REAL": "REAL",
22
+ "INT": "INT",
23
+ "INTEGER": "INT",
24
+ "BIGINT": "BIGINT",
25
+ "SMALLINT": "SMALLINT",
26
+ "TINYINT": "SMALLINT",
27
+ "BIT": "BIT",
28
+ "BOOLEAN": "BIT",
29
+ "DECIMAL": "DECIMAL",
30
+ "NUMERIC": "NUMERIC",
31
+ "MONEY": "DECIMAL",
32
+ "SMALLMONEY": "DECIMAL",
33
+ "UNIQUEIDENTIFIER": "UNIQUEIDENTIFIER",
34
+ "VARBINARY": "VARBINARY(MAX)",
35
+ "BINARY": "BINARY(1)",
36
+ }
37
+
38
+ @classmethod
39
+ def string_type(cls, size: int) -> str:
40
+ return f"varchar({size if size > 0 else '8000'})"
41
+
42
+ def literal(self, value: Any) -> str:
43
+ return "cast('{}' as {})".format(value, self.data_type)
44
+
45
+ @property
46
+ def data_type(self) -> str:
47
+ # Always enforce datetime2 precision
48
+ if self.dtype.lower() == "datetime2":
49
+ return "datetime2(6)"
50
+ if self.is_string():
51
+ return self.string_type(self.string_size())
52
+ elif self.is_numeric():
53
+ return self.numeric_type(self.dtype, self.numeric_precision, self.numeric_scale)
54
+ else:
55
+ return self.dtype
56
+
57
+ def is_string(self) -> bool:
58
+ return self.dtype.lower() in ["varchar", "char"]
59
+
60
+ def is_number(self):
61
+ return any([self.is_integer(), self.is_numeric(), self.is_float()])
62
+
63
+ def is_float(self):
64
+ return self.dtype.lower() in ["float", "real"]
65
+
66
+ def is_integer(self) -> bool:
67
+ return self.dtype.lower() in [
68
+ # real types
69
+ "smallint",
70
+ "integer",
71
+ "bigint",
72
+ "smallserial",
73
+ "serial",
74
+ "bigserial",
75
+ # aliases
76
+ "int2",
77
+ "int4",
78
+ "int8",
79
+ "serial2",
80
+ "serial4",
81
+ "serial8",
82
+ "int",
83
+ ]
84
+
85
+ def is_numeric(self) -> bool:
86
+ return self.dtype.lower() in ["numeric", "decimal", "money", "smallmoney"]
87
+
88
+ def string_size(self) -> int:
89
+ if not self.is_string():
90
+ raise DbtRuntimeError("Called string_size() on non-string field!")
91
+ if self.char_size is None:
92
+ return 8000
93
+ else:
94
+ return int(self.char_size)
95
+
96
+ def can_expand_to(self, other_column: "SQLServerColumn") -> bool:
97
+ if not self.is_string() or not other_column.is_string():
98
+ return False
99
+ return other_column.string_size() > self.string_size()
@@ -0,0 +1,9 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ from dbt.adapters.protocol import AdapterConfig
5
+
6
+
7
+ @dataclass
8
+ class SQLServerConfigs(AdapterConfig):
9
+ auto_provision_aad_principals: Optional[bool] = False