Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/google/adk/sessions/database_session_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
_MARIADB_DIALECT = "mariadb"
_MYSQL_DIALECT = "mysql"
_POSTGRESQL_DIALECT = "postgresql"
_MSSQL_DIALECT = "mssql"
# Dialects whose DATETIME/TIMESTAMP columns do not retain timezone info, so
# timezone-aware datetimes must have their tzinfo stripped before storage. This
# keeps the value written by create_session consistent with the value read back
Expand All @@ -94,6 +95,7 @@
_POSTGRESQL_DIALECT,
_MYSQL_DIALECT,
_MARIADB_DIALECT,
_MSSQL_DIALECT,
)
# Tuple key order for in-process per-session lock maps:
# (app_name, user_id, session_id).
Expand Down
7 changes: 7 additions & 0 deletions src/google/adk/sessions/schemas/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from sqlalchemy import Dialect
from sqlalchemy import Text
from sqlalchemy.dialects import mssql
from sqlalchemy.dialects import mysql
from sqlalchemy.dialects import postgresql
from sqlalchemy.types import DateTime
Expand Down Expand Up @@ -94,6 +95,12 @@ class PreciseTimestamp(TypeDecorator[datetime.datetime]): # type: ignore[misc]
def load_dialect_impl(self, dialect: Dialect) -> TypeEngine[Any]:
if dialect.name == "mysql":
return dialect.type_descriptor(mysql.DATETIME(fsp=6))
if dialect.name == "mssql":
# SQL Server's legacy DATETIME has ~3.33ms precision, which destroys
# the microsecond update marker used by the optimistic-concurrency
# check (a session's second append is falsely rejected as stale).
# DATETIME2(6) retains microseconds.
return dialect.type_descriptor(mssql.DATETIME2(precision=6))
return self.impl_instance

def result_processor(
Expand Down
11 changes: 11 additions & 0 deletions tests/unittests/sessions/test_schemas_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,14 @@ def test_precise_timestamp_result_processor_delegates_non_numeric_values(
process = precise_timestamp.result_processor(_dialect("mysql"), None)

assert process("2026-01-02 03:04:05.123456") == expected


def test_precise_timestamp_uses_datetime2_on_mssql():
"""SQL Server's legacy DATETIME rounds to ~3.33ms, which destroys the
microsecond update marker used by the optimistic-concurrency check."""
from sqlalchemy.dialects import mssql as mssql_dialect

ts = PreciseTimestamp()
impl = ts.load_dialect_impl(mssql_dialect.dialect())
assert isinstance(impl, mssql_dialect.DATETIME2)
assert impl.precision == 6