@@ -82,6 +82,23 @@ def quote_identifier(identifier: str) -> str:
8282 return '"{}"' .format (identifier .replace ('"' , '""' ))
8383
8484
85+ def _row_to_dict (keys : Sequence [str ], row : Sequence [Any ]) -> Dict [str , Any ]:
86+ """
87+ Convert a row plus column names to a dictionary.
88+
89+ Duplicate column names are suffixed with ``_2``, ``_3``... so values are
90+ preserved instead of overwritten.
91+ """
92+ counts : Dict [str , int ] = {}
93+ result : Dict [str , Any ] = {}
94+ for key , value in zip (keys , row ):
95+ count = counts .get (key , 0 ) + 1
96+ counts [key ] = count
97+ final_key = key if count == 1 else "{}_{}" .format (key , count )
98+ result [final_key ] = value
99+ return result
100+
101+
85102try :
86103 import pandas as pd # type: ignore
87104except ImportError :
@@ -548,7 +565,7 @@ def query(
548565 cursor = self .execute (sql , params or tuple ())
549566 keys = [d [0 ] for d in cursor .description ]
550567 for row in cursor :
551- yield dict ( zip ( keys , row ) )
568+ yield _row_to_dict ( keys , row )
552569
553570 def execute (
554571 self , sql : str , parameters : Optional [Union [Sequence , Dict [str , Any ]]] = None
@@ -1445,7 +1462,7 @@ def rows_where(
14451462 cursor = self .db .execute (sql , where_args or [])
14461463 columns = [c [0 ] for c in cursor .description ]
14471464 for row in cursor :
1448- yield dict ( zip ( columns , row ) )
1465+ yield _row_to_dict ( columns , row )
14491466
14501467 def pks_and_rows_where (
14511468 self ,
@@ -2862,7 +2879,7 @@ def search(
28622879 )
28632880 columns = [c [0 ] for c in cursor .description ]
28642881 for row in cursor :
2865- yield dict ( zip ( columns , row ) )
2882+ yield _row_to_dict ( columns , row )
28662883
28672884 def value_or_default (self , key : str , value : Any ) -> Any :
28682885 return self ._defaults [key ] if value is DEFAULT else value
0 commit comments