@@ -845,6 +845,30 @@ def _build_converter_map(self):
845845
846846 return converter_map
847847
848+ def _get_column_and_converter_maps (self ):
849+ """
850+ Get column map and converter map for Row construction (thread-safe).
851+ This centralizes the column map building logic to eliminate duplication
852+ and ensure thread-safe lazy initialization.
853+
854+ Returns:
855+ tuple: (column_map, converter_map)
856+ """
857+ # Thread-safe lazy initialization of column map
858+ column_map = self ._cached_column_map
859+ if column_map is None and self .description :
860+ # Build column map locally first, then assign to cache
861+ column_map = {col_desc [0 ]: i for i , col_desc in enumerate (self .description )}
862+ self ._cached_column_map = column_map
863+
864+ # Fallback to legacy column name map if no cached map
865+ column_map = column_map or getattr (self , '_column_name_map' , None )
866+
867+ # Get cached converter map
868+ converter_map = getattr (self , '_cached_converter_map' , None )
869+
870+ return column_map , converter_map
871+
848872 def _map_data_type (self , sql_type ):
849873 """
850874 Map SQL data type to Python data type.
@@ -1985,11 +2009,8 @@ def fetchone(self) -> Union[None, Row]:
19852009
19862010 self .rowcount = self ._next_row_index
19872011
1988- # Build column map once and cache it
1989- if self ._cached_column_map is None and self .description :
1990- self ._cached_column_map = {col_desc [0 ]: i for i , col_desc in enumerate (self .description )}
1991- column_map = self ._cached_column_map or getattr (self , '_column_name_map' , None )
1992- converter_map = getattr (self , '_cached_converter_map' , None )
2012+ # Get column and converter maps
2013+ column_map , converter_map = self ._get_column_and_converter_maps ()
19932014 return Row (row_data , column_map , cursor = self , converter_map = converter_map )
19942015 except Exception as e :
19952016 # On error, don't increment rownumber - rethrow the error
@@ -2035,13 +2056,10 @@ def fetchmany(self, size: Optional[int] = None) -> List[Row]:
20352056 else :
20362057 self .rowcount = self ._next_row_index
20372058
2038- # Build column map once and cache it
2039- if self ._cached_column_map is None and self .description :
2040- self ._cached_column_map = {col_desc [0 ]: i for i , col_desc in enumerate (self .description )}
2059+ # Get column and converter maps
2060+ column_map , converter_map = self ._get_column_and_converter_maps ()
20412061
20422062 # Convert raw data to Row objects
2043- column_map = self ._cached_column_map or getattr (self , '_column_name_map' , None )
2044- converter_map = getattr (self , '_cached_converter_map' , None )
20452063 return [Row (row_data , column_map , cursor = self , converter_map = converter_map ) for row_data in rows_data ]
20462064 except Exception as e :
20472065 # On error, don't increment rownumber - rethrow the error
@@ -2077,13 +2095,10 @@ def fetchall(self) -> List[Row]:
20772095 else :
20782096 self .rowcount = self ._next_row_index
20792097
2080- # Build column map once and cache it
2081- if self ._cached_column_map is None and self .description :
2082- self ._cached_column_map = {col_desc [0 ]: i for i , col_desc in enumerate (self .description )}
2098+ # Get column and converter maps
2099+ column_map , converter_map = self ._get_column_and_converter_maps ()
20832100
20842101 # Convert raw data to Row objects
2085- column_map = self ._cached_column_map or getattr (self , '_column_name_map' , None )
2086- converter_map = getattr (self , '_cached_converter_map' , None )
20872102 return [Row (row_data , column_map , cursor = self , converter_map = converter_map ) for row_data in rows_data ]
20882103 except Exception as e :
20892104 # On error, don't increment rownumber - rethrow the error
0 commit comments