From bd070da875e142458bef7433b5340773d088ad75 Mon Sep 17 00:00:00 2001 From: Jesse Whitehouse Date: Fri, 22 Sep 2023 17:32:21 -0400 Subject: [PATCH 1/7] Add e2e tests for parameterized queries Signed-off-by: Jesse Whitehouse --- tests/e2e/common/parameterized_query_tests.py | 185 ++++++++++++++++++ tests/e2e/test_driver.py | 3 +- 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 tests/e2e/common/parameterized_query_tests.py diff --git a/tests/e2e/common/parameterized_query_tests.py b/tests/e2e/common/parameterized_query_tests.py new file mode 100644 index 000000000..6bda9fe98 --- /dev/null +++ b/tests/e2e/common/parameterized_query_tests.py @@ -0,0 +1,185 @@ +import pytest +import databricks.sql as sql +from databricks.sql import Error +import pytz + +from decimal import Decimal + +from databricks.sql.utils import DbSqlParameter, DbSqlType +from datetime import datetime + +from databricks.sql.client import Connection + + +class PySQLParameterizedQueryTestSuiteMixin: + """Namespace for tests of server-side parameterized queries""" + + def test_parameterized_query_named_and_inferred_e2e(self): + """Verify that named parameters passed to the database as a dict are returned of the correct type + All types are inferred. + """ + + conn: Connection + + query = """ + SELECT + :p_bool AS col_bool, + :p_int AS col_int, + :p_double AS col_double, + :p_date as col_date, + :p_timestamp as col_timestamp, + :p_str AS col_str + """ + + named_parameters = { + "p_bool": True, + "p_int": 1234, + "p_double": 3.14, + "p_date": datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + "p_timestamp": datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + "p_str": "Hello", + } + with self.connection() as conn: + cursor = conn.cursor() + cursor.execute(query, parameters=named_parameters) + result = cursor.fetchone() + + assert result.col_bool == True + assert result.col_int == 1234 + + # For equality, we use Decimal to quantize these values + assert Decimal(result.col_double).quantize(Decimal("0.00")) == Decimal( + 3.14 + ).quantize(Decimal("0.00")) + + assert result.col_date == datetime( + 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC + ) + assert result.col_timestamp == datetime( + 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC + ) + assert result.col_str == "Hello" + + def test_parameterized_query_named_dict_and_inferred_e2e(self): + """Verify that named parameters passed to the database as a list are returned of the correct type + All types are inferred. + """ + + conn: Connection + + query = """ + SELECT + :p_bool AS col_bool, + :p_int AS col_int, + :p_double AS col_double, + :p_date as col_date, + :p_timestamp as col_timestamp, + :p_str AS col_str + """ + + named_parameters = [ + DbSqlParameter( + name="p_bool", + value=True, + ), + DbSqlParameter( + name="p_int", + value=1234, + ), + DbSqlParameter( + name="p_double", + value=3.14, + ), + DbSqlParameter( + name="p_date", + value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + ), + DbSqlParameter( + name="p_timestamp", + value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + ), + DbSqlParameter(name="p_str", value="Hello"), + ] + + with self.connection() as conn: + cursor = conn.cursor() + cursor.execute(query, parameters=named_parameters) + result = cursor.fetchone() + + assert result.col_bool == True + assert result.col_int == 1234 + + # For equality, we use Decimal to quantize these values + assert Decimal(result.col_double).quantize(Decimal("0.00")) == Decimal( + 3.14 + ).quantize(Decimal("0.00")) + + assert result.col_date == datetime( + 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC + ) + assert result.col_timestamp == datetime( + 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC + ) + assert result.col_str == "Hello" + + def test_parameterized_query_named_dict_and_not_inferred_e2e(self): + """Verify that named parameters passed to the database are returned of the correct type + All types are explicitly set. + """ + + conn: Connection + + query = """ + SELECT + :p_bool AS col_bool, + :p_int AS col_int, + :p_double AS col_double, + :p_date as col_date, + :p_timestamp as col_timestamp, + :p_str AS col_str + """ + + named_parameters = [ + DbSqlParameter(name="p_bool", value=True, type=DbSqlType.BOOLEAN), + DbSqlParameter(name="p_int", value=1234, type=DbSqlType.INTEGER), + DbSqlParameter(name="p_double", value=3.14, type=DbSqlType.FLOAT), + DbSqlParameter( + name="p_date", + value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + type=DbSqlType.DATE, + ), + DbSqlParameter( + name="p_timestamp", + value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + type=DbSqlType.TIMESTAMP, + ), + DbSqlParameter(name="p_str", value="Hello", type=DbSqlType.STRING), + ] + + with self.connection() as conn: + cursor = conn.cursor() + cursor.execute(query, parameters=named_parameters) + result = cursor.fetchone() + + assert result.col_bool == True + assert result.col_int == 1234 + + # For equality, we use Decimal to quantize these values + assert Decimal(result.col_double).quantize(Decimal("0.00")) == Decimal( + 3.14 + ).quantize(Decimal("0.00")) + + # Observe that passing a datetime object with timezone information and the type set to DbSqlType.DATE + # strips away the time and tz info + assert ( + result.col_date + == datetime( + 2023, + 9, + 6, + ).date() + ) + assert result.col_timestamp == datetime( + 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC + ) + assert result.col_str == "Hello" diff --git a/tests/e2e/test_driver.py b/tests/e2e/test_driver.py index 90bf5c3d4..85b6024a2 100644 --- a/tests/e2e/test_driver.py +++ b/tests/e2e/test_driver.py @@ -28,6 +28,7 @@ from tests.e2e.common.retry_test_mixins import Client429ResponseMixin, Client503ResponseMixin from tests.e2e.common.staging_ingestion_tests import PySQLStagingIngestionTestSuiteMixin from tests.e2e.common.retry_test_mixins import PySQLRetryTestsMixin +from tests.e2e.common.parameterized_query_tests import PySQLParameterizedQueryTestSuiteMixin log = logging.getLogger(__name__) @@ -142,7 +143,7 @@ def test_cloud_fetch(self): # Exclude Retry tests because they require specific setups, and LargeQueries too slow for core # tests class PySQLCoreTestSuite(SmokeTestMixin, CoreTestMixin, DecimalTestsMixin, TimestampTestsMixin, - PySQLTestCase, PySQLStagingIngestionTestSuiteMixin, PySQLRetryTestsMixin): + PySQLTestCase, PySQLStagingIngestionTestSuiteMixin, PySQLRetryTestsMixin, PySQLParameterizedQueryTestSuiteMixin): validate_row_value_type = True validate_result = True From 3ce76cea1e50db267c2237a8755ae1f4fdc57769 Mon Sep 17 00:00:00 2001 From: Jesse Whitehouse Date: Fri, 22 Sep 2023 17:35:10 -0400 Subject: [PATCH 2/7] Run isort on test file for clarity Signed-off-by: Jesse Whitehouse --- tests/e2e/common/parameterized_query_tests.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/e2e/common/parameterized_query_tests.py b/tests/e2e/common/parameterized_query_tests.py index 6bda9fe98..1f79c87b5 100644 --- a/tests/e2e/common/parameterized_query_tests.py +++ b/tests/e2e/common/parameterized_query_tests.py @@ -1,14 +1,10 @@ -import pytest -import databricks.sql as sql -from databricks.sql import Error -import pytz - +from datetime import datetime from decimal import Decimal -from databricks.sql.utils import DbSqlParameter, DbSqlType -from datetime import datetime +import pytz from databricks.sql.client import Connection +from databricks.sql.utils import DbSqlParameter, DbSqlType class PySQLParameterizedQueryTestSuiteMixin: From c37f237f0c42f387f2bccc57f79d34c3728a7c12 Mon Sep 17 00:00:00 2001 From: Jesse Whitehouse Date: Fri, 22 Sep 2023 20:59:32 -0400 Subject: [PATCH 3/7] pr check: black the codebase Signed-off-by: Jesse Whitehouse --- src/databricks/sql/thrift_backend.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/databricks/sql/thrift_backend.py b/src/databricks/sql/thrift_backend.py index 93ea04eea..754dcdfdf 100644 --- a/src/databricks/sql/thrift_backend.py +++ b/src/databricks/sql/thrift_backend.py @@ -613,10 +613,7 @@ def _create_arrow_table(self, t_row_set, lz4_compressed, schema_bytes, descripti num_rows, ) = convert_column_based_set_to_arrow_table(t_row_set.columns, description) elif t_row_set.arrowBatches is not None: - ( - arrow_table, - num_rows, - ) = convert_arrow_based_set_to_arrow_table( + (arrow_table, num_rows,) = convert_arrow_based_set_to_arrow_table( t_row_set.arrowBatches, lz4_compressed, schema_bytes ) else: From b5e0726510cd88b022ef8d4090e9ee2c36a1cfc2 Mon Sep 17 00:00:00 2001 From: Jesse Whitehouse Date: Fri, 22 Sep 2023 21:09:30 -0400 Subject: [PATCH 4/7] pr check: black the codebase Signed-off-by: Jesse Whitehouse --- src/databricks/sqlalchemy/dialect/requirements.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/databricks/sqlalchemy/dialect/requirements.py b/src/databricks/sqlalchemy/dialect/requirements.py index 2d4d2b6dc..7da460057 100644 --- a/src/databricks/sqlalchemy/dialect/requirements.py +++ b/src/databricks/sqlalchemy/dialect/requirements.py @@ -24,9 +24,11 @@ def __some_example_requirement(self): import sqlalchemy.testing.exclusions import logging + logger = logging.getLogger(__name__) logger.warning("requirements.py is not currently employed by Databricks dialect") + class Requirements(sqlalchemy.testing.requirements.SuiteRequirements): - pass \ No newline at end of file + pass From 3333ca060e629d1a95babcacfe7f9659c688fce7 Mon Sep 17 00:00:00 2001 From: Jesse Whitehouse Date: Mon, 25 Sep 2023 11:44:37 -0400 Subject: [PATCH 5/7] Update tests to check for inferred dates. Only test_parameterized_query_named_dict_and_not_inferred_e2e passes because we don't infer anything here. Signed-off-by: Jesse Whitehouse --- tests/e2e/common/parameterized_query_tests.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/e2e/common/parameterized_query_tests.py b/tests/e2e/common/parameterized_query_tests.py index 1f79c87b5..eaf22086b 100644 --- a/tests/e2e/common/parameterized_query_tests.py +++ b/tests/e2e/common/parameterized_query_tests.py @@ -31,7 +31,7 @@ def test_parameterized_query_named_and_inferred_e2e(self): "p_bool": True, "p_int": 1234, "p_double": 3.14, - "p_date": datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + "p_date": datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC).date(), "p_timestamp": datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), "p_str": "Hello", } @@ -50,7 +50,7 @@ def test_parameterized_query_named_and_inferred_e2e(self): assert result.col_date == datetime( 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC - ) + ).date() assert result.col_timestamp == datetime( 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC ) @@ -88,7 +88,7 @@ def test_parameterized_query_named_dict_and_inferred_e2e(self): ), DbSqlParameter( name="p_date", - value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC).date(), ), DbSqlParameter( name="p_timestamp", @@ -112,7 +112,7 @@ def test_parameterized_query_named_dict_and_inferred_e2e(self): assert result.col_date == datetime( 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC - ) + ).date() assert result.col_timestamp == datetime( 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC ) @@ -141,7 +141,7 @@ def test_parameterized_query_named_dict_and_not_inferred_e2e(self): DbSqlParameter(name="p_double", value=3.14, type=DbSqlType.FLOAT), DbSqlParameter( name="p_date", - value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), + value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC).date(), type=DbSqlType.DATE, ), DbSqlParameter( From 554623ff52246715dd351e48f88e3076608d9289 Mon Sep 17 00:00:00 2001 From: Jesse Whitehouse Date: Mon, 25 Sep 2023 11:45:57 -0400 Subject: [PATCH 6/7] Update type map to allow it to infer datetime.date objects Signed-off-by: Jesse Whitehouse --- src/databricks/sql/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/databricks/sql/utils.py b/src/databricks/sql/utils.py index b4ad99022..e6cd703b4 100644 --- a/src/databricks/sql/utils.py +++ b/src/databricks/sql/utils.py @@ -529,6 +529,7 @@ def infer_types(params: list[DbSqlParameter]): int: DbSqlType.INTEGER, float: DbSqlType.FLOAT, datetime.datetime: DbSqlType.TIMESTAMP, + datetime.date: DbSqlType.DATE, bool: DbSqlType.BOOLEAN, } newParams = copy.deepcopy(params) From a8841f884b8576561961cf69ec356ecf15ca6752 Mon Sep 17 00:00:00 2001 From: Jesse Whitehouse Date: Mon, 25 Sep 2023 13:52:25 -0400 Subject: [PATCH 7/7] PR: Split out tests into individual units of work. One test per primitive, parameter type, and inferrence level. Signed-off-by: Jesse Whitehouse --- tests/e2e/common/parameterized_query_tests.py | 297 ++++++++---------- 1 file changed, 130 insertions(+), 167 deletions(-) diff --git a/tests/e2e/common/parameterized_query_tests.py b/tests/e2e/common/parameterized_query_tests.py index eaf22086b..e6302aa32 100644 --- a/tests/e2e/common/parameterized_query_tests.py +++ b/tests/e2e/common/parameterized_query_tests.py @@ -1,5 +1,6 @@ -from datetime import datetime +import datetime from decimal import Decimal +from typing import Dict, List, Tuple, Union import pytz @@ -10,172 +11,134 @@ class PySQLParameterizedQueryTestSuiteMixin: """Namespace for tests of server-side parameterized queries""" - def test_parameterized_query_named_and_inferred_e2e(self): - """Verify that named parameters passed to the database as a dict are returned of the correct type - All types are inferred. - """ - - conn: Connection - - query = """ - SELECT - :p_bool AS col_bool, - :p_int AS col_int, - :p_double AS col_double, - :p_date as col_date, - :p_timestamp as col_timestamp, - :p_str AS col_str - """ - - named_parameters = { - "p_bool": True, - "p_int": 1234, - "p_double": 3.14, - "p_date": datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC).date(), - "p_timestamp": datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), - "p_str": "Hello", - } - with self.connection() as conn: - cursor = conn.cursor() - cursor.execute(query, parameters=named_parameters) - result = cursor.fetchone() - - assert result.col_bool == True - assert result.col_int == 1234 - - # For equality, we use Decimal to quantize these values - assert Decimal(result.col_double).quantize(Decimal("0.00")) == Decimal( - 3.14 - ).quantize(Decimal("0.00")) - - assert result.col_date == datetime( - 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC - ).date() - assert result.col_timestamp == datetime( - 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC - ) - assert result.col_str == "Hello" - - def test_parameterized_query_named_dict_and_inferred_e2e(self): - """Verify that named parameters passed to the database as a list are returned of the correct type - All types are inferred. - """ - - conn: Connection - - query = """ - SELECT - :p_bool AS col_bool, - :p_int AS col_int, - :p_double AS col_double, - :p_date as col_date, - :p_timestamp as col_timestamp, - :p_str AS col_str - """ - - named_parameters = [ - DbSqlParameter( - name="p_bool", - value=True, - ), - DbSqlParameter( - name="p_int", - value=1234, - ), - DbSqlParameter( - name="p_double", - value=3.14, - ), - DbSqlParameter( - name="p_date", - value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC).date(), - ), - DbSqlParameter( - name="p_timestamp", - value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), - ), - DbSqlParameter(name="p_str", value="Hello"), - ] + QUERY = "SELECT :p AS col" + def _get_one_result(self, query: str, parameters: Union[Dict, List[Dict]]) -> Tuple: with self.connection() as conn: - cursor = conn.cursor() - cursor.execute(query, parameters=named_parameters) - result = cursor.fetchone() - - assert result.col_bool == True - assert result.col_int == 1234 - - # For equality, we use Decimal to quantize these values - assert Decimal(result.col_double).quantize(Decimal("0.00")) == Decimal( - 3.14 - ).quantize(Decimal("0.00")) - - assert result.col_date == datetime( - 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC - ).date() - assert result.col_timestamp == datetime( - 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC - ) - assert result.col_str == "Hello" - - def test_parameterized_query_named_dict_and_not_inferred_e2e(self): - """Verify that named parameters passed to the database are returned of the correct type - All types are explicitly set. - """ - - conn: Connection - - query = """ - SELECT - :p_bool AS col_bool, - :p_int AS col_int, - :p_double AS col_double, - :p_date as col_date, - :p_timestamp as col_timestamp, - :p_str AS col_str - """ - - named_parameters = [ - DbSqlParameter(name="p_bool", value=True, type=DbSqlType.BOOLEAN), - DbSqlParameter(name="p_int", value=1234, type=DbSqlType.INTEGER), - DbSqlParameter(name="p_double", value=3.14, type=DbSqlType.FLOAT), - DbSqlParameter( - name="p_date", - value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC).date(), - type=DbSqlType.DATE, - ), - DbSqlParameter( - name="p_timestamp", - value=datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC), - type=DbSqlType.TIMESTAMP, - ), - DbSqlParameter(name="p_str", value="Hello", type=DbSqlType.STRING), - ] + with conn.cursor() as cursor: + cursor.execute(query, parameters=parameters) + return cursor.fetchone() - with self.connection() as conn: - cursor = conn.cursor() - cursor.execute(query, parameters=named_parameters) - result = cursor.fetchone() - - assert result.col_bool == True - assert result.col_int == 1234 - - # For equality, we use Decimal to quantize these values - assert Decimal(result.col_double).quantize(Decimal("0.00")) == Decimal( - 3.14 - ).quantize(Decimal("0.00")) - - # Observe that passing a datetime object with timezone information and the type set to DbSqlType.DATE - # strips away the time and tz info - assert ( - result.col_date - == datetime( - 2023, - 9, - 6, - ).date() - ) - assert result.col_timestamp == datetime( - 2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC - ) - assert result.col_str == "Hello" + def _quantize(self, input: Union[float, int], place_value=2) -> Decimal: + + return Decimal(str(input)).quantize(Decimal("0." + "0" * place_value)) + + def test_primitive_inferred_bool(self): + + params = {"p": True} + result = self._get_one_result(self.QUERY, params) + assert result.col == True + + def test_primitive_inferred_integer(self): + + params = {"p": 1} + result = self._get_one_result(self.QUERY, params) + assert result.col == 1 + + def test_primitive_inferred_double(self): + + params = {"p": 3.14} + result = self._get_one_result(self.QUERY, params) + assert self._quantize(result.col) == self._quantize(3.14) + + def test_primitive_inferred_date(self): + + # DATE in Databricks is mapped into a datetime.date object in Python + date_value = datetime.date(2023, 9, 6) + params = {"p": date_value} + result = self._get_one_result(self.QUERY, params) + assert result.col == date_value + + def test_primitive_inferred_timestamp(self): + + # TIMESTAMP in Databricks is mapped into a datetime.datetime object in Python + date_value = datetime.datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC) + params = {"p": date_value} + result = self._get_one_result(self.QUERY, params) + assert result.col == date_value + + def test_primitive_inferred_string(self): + + params = {"p": "Hello"} + result = self._get_one_result(self.QUERY, params) + assert result.col == "Hello" + + def test_dbsqlparam_inferred_bool(self): + + params = [DbSqlParameter(name="p", value=True, type=None)] + result = self._get_one_result(self.QUERY, params) + assert result.col == True + + def test_dbsqlparam_inferred_integer(self): + + params = [DbSqlParameter(name="p", value=1, type=None)] + result = self._get_one_result(self.QUERY, params) + assert result.col == 1 + + def test_dbsqlparam_inferred_double(self): + + params = [DbSqlParameter(name="p", value=3.14, type=None)] + result = self._get_one_result(self.QUERY, params) + assert self._quantize(result.col) == self._quantize(3.14) + + def test_dbsqlparam_inferred_date(self): + + # DATE in Databricks is mapped into a datetime.date object in Python + date_value = datetime.date(2023, 9, 6) + params = [DbSqlParameter(name="p", value=date_value, type=None)] + result = self._get_one_result(self.QUERY, params) + assert result.col == date_value + + def test_dbsqlparam_inferred_timestamp(self): + + # TIMESTAMP in Databricks is mapped into a datetime.datetime object in Python + date_value = datetime.datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC) + params = [DbSqlParameter(name="p", value=date_value, type=None)] + result = self._get_one_result(self.QUERY, params) + assert result.col == date_value + + def test_dbsqlparam_inferred_string(self): + + params = [DbSqlParameter(name="p", value="Hello", type=None)] + result = self._get_one_result(self.QUERY, params) + assert result.col == "Hello" + + def test_dbsqlparam_explicit_bool(self): + + params = [DbSqlParameter(name="p", value=True, type=DbSqlType.BOOLEAN)] + result = self._get_one_result(self.QUERY, params) + assert result.col == True + + def test_dbsqlparam_explicit_integer(self): + + params = [DbSqlParameter(name="p", value=1, type=DbSqlType.INTEGER)] + result = self._get_one_result(self.QUERY, params) + assert result.col == 1 + + def test_dbsqlparam_explicit_double(self): + + params = [DbSqlParameter(name="p", value=3.14, type=DbSqlType.FLOAT)] + result = self._get_one_result(self.QUERY, params) + assert self._quantize(result.col) == self._quantize(3.14) + + def test_dbsqlparam_explicit_date(self): + + # DATE in Databricks is mapped into a datetime.date object in Python + date_value = datetime.date(2023, 9, 6) + params = [DbSqlParameter(name="p", value=date_value, type=DbSqlType.DATE)] + result = self._get_one_result(self.QUERY, params) + assert result.col == date_value + + def test_dbsqlparam_explicit_timestamp(self): + + # TIMESTAMP in Databricks is mapped into a datetime.datetime object in Python + date_value = datetime.datetime(2023, 9, 6, 3, 14, 27, 843, tzinfo=pytz.UTC) + params = [DbSqlParameter(name="p", value=date_value, type=DbSqlType.TIMESTAMP)] + result = self._get_one_result(self.QUERY, params) + assert result.col == date_value + + def test_dbsqlparam_explicit_string(self): + + params = [DbSqlParameter(name="p", value="Hello", type=DbSqlType.STRING)] + result = self._get_one_result(self.QUERY, params) + assert result.col == "Hello"