@@ -209,6 +209,103 @@ def test_complex_rejected_as_data_error(self, cluster_address: str) -> None:
209209 with pytest .raises (DataError ):
210210 c .execute ("SELECT ?" , [complex (1 , 2 )])
211211
212+ def test_uuid_rejected_as_data_error (self , cluster_address : str ) -> None :
213+ """UUID is not a wire-recognized type — must surface as DataError.
214+ Common in callers porting from psycopg/asyncpg which both
215+ accept UUID."""
216+ from uuid import UUID
217+
218+ from dqlitedbapi .exceptions import DataError
219+
220+ with connect (cluster_address , database = "test_bind_types" ) as conn :
221+ c = conn .cursor ()
222+ with pytest .raises (DataError ):
223+ c .execute (
224+ "SELECT ?" ,
225+ [UUID ("12345678-1234-5678-1234-567812345678" )],
226+ )
227+
228+ def test_path_rejected_as_data_error (self , cluster_address : str ) -> None :
229+ """``pathlib.Path`` (sometimes used for filename columns) must
230+ surface as DataError so a caller is steered to ``str(path)``."""
231+ from pathlib import Path
232+
233+ from dqlitedbapi .exceptions import DataError
234+
235+ with connect (cluster_address , database = "test_bind_types" ) as conn :
236+ c = conn .cursor ()
237+ with pytest .raises (DataError ):
238+ c .execute ("SELECT ?" , [Path ("/tmp/foo" )])
239+
240+ def test_array_array_rejected_as_data_error (self , cluster_address : str ) -> None :
241+ """``array.array`` is bytes-like but not in the accepted
242+ BLOB-input set. Must surface as DataError."""
243+ from array import array
244+
245+ from dqlitedbapi .exceptions import DataError
246+
247+ with connect (cluster_address , database = "test_bind_types" ) as conn :
248+ c = conn .cursor ()
249+ with pytest .raises (DataError ):
250+ c .execute ("SELECT ?" , [array ("b" , b"hello" )])
251+
252+ def test_intenum_round_trips_as_int (self , cluster_address : str ) -> None :
253+ """``enum.IntEnum`` is an ``int`` subclass; the wire encoder
254+ accepts it as INTEGER. Pin observed behavior so a future
255+ refactor that tightened the type check (rejecting subclasses)
256+ is a deliberate decision, not an accident."""
257+ from enum import IntEnum
258+
259+ class _Color (IntEnum ):
260+ RED = 1
261+
262+ with connect (cluster_address , database = "test_bind_types" ) as conn :
263+ c = conn .cursor ()
264+ c .execute ("SELECT ?" , [_Color .RED ])
265+ row = c .fetchone ()
266+ assert row == (1 ,) or row == (int (_Color .RED ),)
267+
268+
269+ @pytest .mark .integration
270+ class TestBindBoundaryDataErrors :
271+ """Boundary inputs that must surface at the DBAPI as ``DataError``
272+ (not as raw ValueError / EncodeError leaking from the wire layer).
273+ The wire encoder enforces caps; the dbapi's ``_call_client``
274+ wraps the wire's ValueError into PEP 249 ``DataError``. Pin the
275+ end-to-end contract so a future narrowing of the wrap cannot
276+ silently let a wire exception leak past the dbapi boundary."""
277+
278+ @pytest .mark .parametrize (
279+ "value" ,
280+ [2 ** 63 , - (2 ** 63 ) - 1 , 2 ** 63 + 1 , 2 ** 100 , - (2 ** 100 )],
281+ )
282+ def test_bind_int_over_int64_raises_data_error (self , cluster_address : str , value : int ) -> None :
283+ from dqlitedbapi .exceptions import DataError
284+
285+ with connect (cluster_address , database = "test_bind_overflow" ) as conn :
286+ c = conn .cursor ()
287+ with pytest .raises (DataError ):
288+ c .execute ("SELECT ?" , [value ])
289+
290+ @pytest .mark .parametrize ("value" , [2 ** 63 - 1 , - (2 ** 63 ), 0 , 1 , - 1 ])
291+ def test_bind_int_at_int64_boundary_succeeds (self , cluster_address : str , value : int ) -> None :
292+ with connect (cluster_address , database = "test_bind_overflow" ) as conn :
293+ c = conn .cursor ()
294+ c .execute ("SELECT ?" , [value ])
295+ assert c .fetchone () == (value ,)
296+
297+ def test_bind_blob_over_cap_raises_data_error (self , cluster_address : str ) -> None :
298+ """A bind value larger than the wire-layer 16 MiB BLOB cap
299+ must surface as ``DataError`` — never as a raw EncodeError or
300+ a silent truncation."""
301+ from dqlitedbapi .exceptions import DataError
302+
303+ big = b"x" * (16 * 1024 * 1024 + 1 )
304+ with connect (cluster_address , database = "test_bind_overflow" ) as conn :
305+ c = conn .cursor ()
306+ with pytest .raises (DataError ):
307+ c .execute ("SELECT ?" , [big ])
308+
212309
213310@pytest .mark .integration
214311class TestCursorDescriptionEdgeCases :
0 commit comments