Skip to content

Commit 829b799

Browse files
feat: support float32 parameters in dbapi (#1245)
* feat: support float32 parameters in dbapi dbapi should not add an explicit type code when a parameter of type float is encountered. Instead, it should rely on Spanner to infer the correct type. This way, both FLOAT32 and FLOAT64 can be used with the Python float type. Updates googleapis/python-spanner-sqlalchemy#409 * chore: remove whitespaces --------- Co-authored-by: Sri Harsha CH <57220027+harshachinta@users.noreply.github.com>
1 parent 5e8ca94 commit 829b799

File tree

3 files changed

+55
-4
lines changed

3 files changed

+55
-4
lines changed

google/cloud/spanner_dbapi/parse_utils.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,19 @@
2929
from .types import DateStr, TimestampStr
3030
from .utils import sanitize_literals_for_upload
3131

32+
# Note: This mapping deliberately does not contain a value for float.
33+
# The reason for that is that it is better to just let Spanner determine
34+
# the parameter type instead of specifying one explicitly. The reason for
35+
# this is that if the client specifies FLOAT64, and the actual column that
36+
# the parameter is used for is of type FLOAT32, then Spanner will return an
37+
# error. If however the client does not specify a type, then Spanner will
38+
# automatically choose the appropriate type based on the column where the
39+
# value will be inserted/updated or that it will be compared with.
3240
TYPES_MAP = {
3341
bool: spanner.param_types.BOOL,
3442
bytes: spanner.param_types.BYTES,
3543
str: spanner.param_types.STRING,
3644
int: spanner.param_types.INT64,
37-
float: spanner.param_types.FLOAT64,
3845
datetime.datetime: spanner.param_types.TIMESTAMP,
3946
datetime.date: spanner.param_types.DATE,
4047
DateStr: spanner.param_types.DATE,

tests/system/test_dbapi.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
14+
import base64
1515
import datetime
1616
from collections import defaultdict
17+
1718
import pytest
1819
import time
20+
import decimal
1921

2022
from google.cloud import spanner_v1
2123
from google.cloud._helpers import UTC
@@ -50,7 +52,22 @@
5052
SQL SECURITY INVOKER
5153
AS
5254
SELECT c.email
53-
FROM contacts AS c;"""
55+
FROM contacts AS c;
56+
57+
CREATE TABLE all_types (
58+
id int64,
59+
col_bool bool,
60+
col_bytes bytes(max),
61+
col_date date,
62+
col_float32 float32,
63+
col_float64 float64,
64+
col_int64 int64,
65+
col_json json,
66+
col_numeric numeric,
67+
col_string string(max),
68+
coL_timestamp timestamp,
69+
) primary key (col_int64);
70+
"""
5471

5572
DDL_STATEMENTS = [stmt.strip() for stmt in DDL.split(";") if stmt.strip()]
5673

@@ -1602,3 +1619,29 @@ def test_list_tables(self, include_views):
16021619
def test_invalid_statement_error(self):
16031620
with pytest.raises(ProgrammingError):
16041621
self._cursor.execute("-- comment only")
1622+
1623+
def test_insert_all_types(self):
1624+
"""Test inserting all supported data types"""
1625+
1626+
self._conn.autocommit = True
1627+
self._cursor.execute(
1628+
"""
1629+
INSERT INTO all_types (id, col_bool, col_bytes, col_date, col_float32, col_float64,
1630+
col_int64, col_json, col_numeric, col_string, col_timestamp)
1631+
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
1632+
""",
1633+
(
1634+
1,
1635+
True,
1636+
base64.b64encode(b"test-bytes"),
1637+
datetime.date(2024, 12, 3),
1638+
3.14,
1639+
3.14,
1640+
123,
1641+
JsonObject({"key": "value"}),
1642+
decimal.Decimal("3.14"),
1643+
"test-string",
1644+
datetime.datetime(2024, 12, 3, 17, 30, 14),
1645+
),
1646+
)
1647+
assert self._cursor.rowcount == 1

tests/unit/spanner_dbapi/test_parse_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ def test_get_param_types(self):
218218
params = {
219219
"a1": 10,
220220
"b1": "string",
221+
# Note: We only want a value and not a type for this.
222+
# Instead, we let Spanner infer the correct type (FLOAT64 or FLOAT32)
221223
"c1": 10.39,
222224
"d1": TimestampStr("2005-08-30T01:01:01.000001Z"),
223225
"e1": DateStr("2019-12-05"),
@@ -232,7 +234,6 @@ def test_get_param_types(self):
232234
want_types = {
233235
"a1": param_types.INT64,
234236
"b1": param_types.STRING,
235-
"c1": param_types.FLOAT64,
236237
"d1": param_types.TIMESTAMP,
237238
"e1": param_types.DATE,
238239
"f1": param_types.BOOL,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy