diff --git a/common/database/database_connection.cpp b/common/database/database_connection.cpp
index 118a8091db..e195502c01 100644
--- a/common/database/database_connection.cpp
+++ b/common/database/database_connection.cpp
@@ -448,7 +448,7 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
                 {
                     aResult[column] = fmt::format( "{:G}", results.get<double>( i ) );
                 }
-                catch( nanodbc::null_access_error& e )
+                catch( nanodbc::null_access_error& )
                 {
                     // Column was empty (null)
                     aResult[column] = std::string();
@@ -498,6 +498,8 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
     {
         wxLogTrace( traceDatabase, wxT( "SelectAll: `%s` - cache hit" ), aTable );
 
+        aResults.reserve( cacheEntry.size() );
+
         for( auto &[ key, row ] : cacheEntry )
             aResults.emplace_back( row );
 
@@ -605,7 +607,7 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
                 {
                     result[column] = fmt::format( "{:G}", results.get<double>( j ) );
                 }
-                catch( nanodbc::null_access_error& e )
+                catch( nanodbc::null_access_error& )
                 {
                     // Column was empty (null)
                     result[column] = std::string();
diff --git a/common/database/database_lib_settings.cpp b/common/database/database_lib_settings.cpp
index f4685194f2..39929e7807 100644
--- a/common/database/database_lib_settings.cpp
+++ b/common/database/database_lib_settings.cpp
@@ -32,6 +32,17 @@
 const int dblibSchemaVersion = 1;
 
 
+DATABASE_FIELD_MAPPING::DATABASE_FIELD_MAPPING( std::string aColumn, std::string aName,
+                                                bool aVisibleOnAdd, bool aVisibleInChooser,
+                                                bool aShowName, bool aInheritProperties ) :
+        column( aColumn ),
+        name( aName ), name_wx( aName.c_str(), wxConvUTF8 ), visible_on_add( aVisibleOnAdd ),
+        visible_in_chooser( aVisibleInChooser ), show_name( aShowName ),
+        inherit_properties( aInheritProperties )
+{
+}
+
+
 DATABASE_LIB_SETTINGS::DATABASE_LIB_SETTINGS( const std::string& aFilename ) :
         JSON_SETTINGS( aFilename, SETTINGS_LOC::NONE, dblibSchemaVersion )
 {
@@ -113,11 +124,8 @@ DATABASE_LIB_SETTINGS::DATABASE_LIB_SETTINGS( const std::string& aFilename ) :
                         bool inherit   = fetchOrDefault<bool>( fieldJson, "inherit_properties" );
 
                         table.fields.emplace_back(
-                                DATABASE_FIELD_MAPPING(
-                                {
-                                    column, name, visible_on_add, visible_in_chooser, show_name,
-                                    inherit
-                                } ) );
+                                DATABASE_FIELD_MAPPING( column, name, visible_on_add,
+                                                        visible_in_chooser, show_name, inherit ) );
                     }
                 }
 
diff --git a/common/string_utils.cpp b/common/string_utils.cpp
index 02d9bbe4f4..675da328e8 100644
--- a/common/string_utils.cpp
+++ b/common/string_utils.cpp
@@ -313,40 +313,40 @@ wxString UnescapeString( const wxString& aSource )
                 }
                 else
                 {
-                    token.append( ch );
+                    token << ch;
                 }
             }
 
             if( !terminated )
             {
-                newbuf.append( wxT( "{" ) + UnescapeString( token ) );
+                newbuf << wxT( "{" ) << UnescapeString( token );
             }
             else if( prev == '$' || prev == '~' || prev == '^' || prev == '_' )
             {
-                newbuf.append( wxT( "{" ) + UnescapeString( token ) + wxT( "}" ) );
+                newbuf << wxT( "{" ) << UnescapeString( token ) << wxT( "}" );
             }
-            else if( token == wxT( "dblquote" ) )  newbuf.append( wxT( "\"" ) );
-            else if( token == wxT( "quote" ) )     newbuf.append( wxT( "'" ) );
-            else if( token == wxT( "lt" ) )        newbuf.append( wxT( "<" ) );
-            else if( token == wxT( "gt" ) )        newbuf.append( wxT( ">" ) );
-            else if( token == wxT( "backslash" ) ) newbuf.append( wxT( "\\" ) );
-            else if( token == wxT( "slash" ) )     newbuf.append( wxT( "/" ) );
-            else if( token == wxT( "bar" ) )       newbuf.append( wxT( "|" ) );
-            else if( token == wxT( "comma" ) )     newbuf.append( wxT( "," ) );
-            else if( token == wxT( "colon" ) )     newbuf.append( wxT( ":" ) );
-            else if( token == wxT( "space" ) )     newbuf.append( wxT( " " ) );
-            else if( token == wxT( "dollar" ) )    newbuf.append( wxT( "$" ) );
-            else if( token == wxT( "tab" ) )       newbuf.append( wxT( "\t" ) );
-            else if( token == wxT( "return" ) )    newbuf.append( wxT( "\n" ) );
-            else if( token == wxT( "brace" ) )     newbuf.append( wxT( "{" ) );
+            else if( token == wxT( "dblquote" ) )  newbuf << wxT( "\"" );
+            else if( token == wxT( "quote" ) )     newbuf << wxT( "'" );
+            else if( token == wxT( "lt" ) )        newbuf << wxT( "<" );
+            else if( token == wxT( "gt" ) )        newbuf << wxT( ">" );
+            else if( token == wxT( "backslash" ) ) newbuf << wxT( "\\" );
+            else if( token == wxT( "slash" ) )     newbuf << wxT( "/" );
+            else if( token == wxT( "bar" ) )       newbuf << wxT( "|" );
+            else if( token == wxT( "comma" ) )     newbuf << wxT( "," );
+            else if( token == wxT( "colon" ) )     newbuf << wxT( ":" );
+            else if( token == wxT( "space" ) )     newbuf << wxT( " " );
+            else if( token == wxT( "dollar" ) )    newbuf << wxT( "$" );
+            else if( token == wxT( "tab" ) )       newbuf << wxT( "\t" );
+            else if( token == wxT( "return" ) )    newbuf << wxT( "\n" );
+            else if( token == wxT( "brace" ) )     newbuf << wxT( "{" );
             else
             {
-                newbuf.append( wxT( "{" ) + UnescapeString( token ) + wxT( "}" ) );
+                newbuf << wxT( "{" ) << UnescapeString( token ) << wxT( "}" );
             }
         }
         else
         {
-            newbuf.append( ch );
+            newbuf << ch;
         }
     }
 
@@ -785,11 +785,14 @@ int StrNumCmp( const wxString& aString1, const wxString& aString2, bool aIgnoreC
         // Any numerical comparisons to here are identical.
         if( aIgnoreCase )
         {
-            if( wxToupper( c1 ) < wxToupper( c2 ) )
-                return -1;
+            if( c1 != c2 )
+            {
+                wxUniChar uc1 = wxToupper( c1 );
+                wxUniChar uc2 = wxToupper( c2 );
 
-            if( wxToupper( c1 ) > wxToupper( c2 ) )
-                return 1;
+                if( uc1 != uc2 )
+                    return uc1 < uc2 ? -1 : 1;
+            }
         }
         else
         {
diff --git a/common/template_fieldnames.cpp b/common/template_fieldnames.cpp
index 4377e2a9e6..b5a75a796c 100644
--- a/common/template_fieldnames.cpp
+++ b/common/template_fieldnames.cpp
@@ -54,8 +54,16 @@ const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx, bool aTra
         case FOOTPRINT_FIELD:   return s_CanonicalFootprint;   // The footprint for use with Pcbnew
         case DATASHEET_FIELD:   return s_CanonicalDatasheet;   // Link to a datasheet for symbol
         case DESCRIPTION_FIELD: return s_CanonicalDescription; // The symbol description
-        default:                return wxString::Format( wxT( "Field%d" ), aFieldNdx );
+        default: break;
         }
+
+        wxString str( wxS( "Field" ) );
+#if wxUSE_UNICODE_WCHAR
+        str << std::to_wstring( aFieldNdx );
+#else
+        str << std::to_string( aFieldNdx );
+#endif
+        return str;
     }
 
     switch( aFieldNdx )
diff --git a/eeschema/sch_io/database/sch_io_database.cpp b/eeschema/sch_io/database/sch_io_database.cpp
index ff02badc2f..d8e2b47b69 100644
--- a/eeschema/sch_io/database/sch_io_database.cpp
+++ b/eeschema/sch_io/database/sch_io_database.cpp
@@ -568,6 +568,9 @@ LIB_SYMBOL* SCH_IO_DATABASE::loadSymbolFromRow( const wxString& aSymbolName,
     for( LIB_FIELD* field : fields )
         fieldsMap[field->GetName()] = field;
 
+    static const wxString c_valueFieldName( wxS( "Value" ) );
+    static const wxString c_datasheetFieldName( wxS( "Datasheet" ) );
+
     for( const DATABASE_FIELD_MAPPING& mapping : aTable.fields )
     {
         if( !aRow.count( mapping.column ) )
@@ -577,7 +580,7 @@ LIB_SYMBOL* SCH_IO_DATABASE::loadSymbolFromRow( const wxString& aSymbolName,
             continue;
         }
 
-        std:: string strValue;
+        std::string strValue;
 
         try
         {
@@ -589,7 +592,7 @@ LIB_SYMBOL* SCH_IO_DATABASE::loadSymbolFromRow( const wxString& aSymbolName,
 
         wxString value( strValue.c_str(), wxConvUTF8 );
 
-        if( mapping.name == wxT( "Value" ) )
+        if( mapping.name_wx == c_valueFieldName )
         {
             LIB_FIELD& field = symbol->GetValueField();
             field.SetText( value );
@@ -601,7 +604,7 @@ LIB_SYMBOL* SCH_IO_DATABASE::loadSymbolFromRow( const wxString& aSymbolName,
             }
             continue;
         }
-        else if( mapping.name == wxT( "Datasheet" ) )
+        else if( mapping.name_wx == c_datasheetFieldName )
         {
             LIB_FIELD& field = symbol->GetDatasheetField();
             field.SetText( value );
@@ -621,16 +624,16 @@ LIB_SYMBOL* SCH_IO_DATABASE::loadSymbolFromRow( const wxString& aSymbolName,
         LIB_FIELD* field;
         bool isNew = false;
 
-        if( fieldsMap.count( mapping.name ) )
+        if( fieldsMap.count( mapping.name_wx ) )
         {
-            field = fieldsMap[mapping.name];
+            field = fieldsMap[mapping.name_wx];
         }
         else
         {
             field = new LIB_FIELD( symbol->GetNextAvailableFieldId() );
-            field->SetName( mapping.name );
+            field->SetName( mapping.name_wx );
             isNew = true;
-            fieldsMap[mapping.name] = field;
+            fieldsMap[mapping.name_wx] = field;
         }
 
         if( !mapping.inherit_properties || isNew )
@@ -643,13 +646,15 @@ LIB_SYMBOL* SCH_IO_DATABASE::loadSymbolFromRow( const wxString& aSymbolName,
         field->SetText( value );
 
         if( isNew )
-            symbol->AddField( field );
+            symbol->AddDrawItem( field, false );
 
-        m_customFields.insert( mapping.name );
+        m_customFields.insert( mapping.name_wx );
 
         if( mapping.visible_in_chooser )
-            m_defaultShownFields.insert( mapping.name );
+            m_defaultShownFields.insert( mapping.name_wx );
     }
 
+    symbol->GetDrawItems().sort();
+
     return symbol;
 }
diff --git a/eeschema/sim/sim_model.cpp b/eeschema/sim/sim_model.cpp
index dcb7d78b51..0dd6c5574b 100644
--- a/eeschema/sim/sim_model.cpp
+++ b/eeschema/sim/sim_model.cpp
@@ -1644,12 +1644,21 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
     wxString              prefix = aSymbol.GetPrefix();
     T_field*              valueField = aSymbol.FindField( wxT( "Value" ) );
     std::vector<LIB_PIN*> sourcePins = aSymbol.GetAllLibPins();
+    bool                  sourcePinsSorted = false;
 
-    std::sort( sourcePins.begin(), sourcePins.end(),
-               []( const LIB_PIN* lhs, const LIB_PIN* rhs )
-               {
-                   return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
-               } );
+    auto lazySortSourcePins = [&sourcePins, &sourcePinsSorted]()
+    {
+        if( !sourcePinsSorted )
+        {
+            std::sort( sourcePins.begin(), sourcePins.end(),
+                       []( const LIB_PIN* lhs, const LIB_PIN* rhs )
+                       {
+                           return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
+                       } );
+        }
+
+        sourcePinsSorted = true;
+    };
 
     FIELD_INFO deviceInfo;
     FIELD_INFO modelInfo;
@@ -1740,6 +1749,8 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
 
             wxStringSplit( legacyPins->GetText(), pinIndexes, ' ' );
 
+            lazySortSourcePins();
+
             if( isPassive && pinIndexes.size() == 2 && sourcePins.size() == 2 )
             {
                 if( pinIndexes[0] == wxT( "2" ) )
@@ -1800,6 +1811,8 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
         model = model.BeforeFirst( ' ', &modelLineParams );
         modelInfo.m_Text = model;
 
+        lazySortSourcePins();
+
         SIM_LIBRARY::MODEL simModel = libMgr.CreateModel( lib, model.ToStdString(),
                                                           emptyFields, sourcePins, reporter );
 
@@ -1873,6 +1886,8 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
 
                         if( pinMapInfo.IsEmpty() )
                         {
+                            lazySortSourcePins();
+
                             // Generate a default pin map from the SIM_MODEL's pins
                             simModel->createPins( sourcePins );
                             pinMapInfo.m_Text = wxString( simModel->Serializer().GeneratePins() );
@@ -1979,7 +1994,10 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
         // the default pin map from the symbol's pins.
 
         if( pinMapInfo.IsEmpty() )
+        {
+            lazySortSourcePins();
             pinMapInfo.m_Text = generateDefaultPinMapFromSymbol( sourcePins );
+        }
     }
 
     if( !pinMapInfo.IsEmpty() )
diff --git a/eeschema/symbol_tree_model_adapter.cpp b/eeschema/symbol_tree_model_adapter.cpp
index 723930a5d3..32ceb3fb07 100644
--- a/eeschema/symbol_tree_model_adapter.cpp
+++ b/eeschema/symbol_tree_model_adapter.cpp
@@ -163,13 +163,15 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector<wxString>& aNick
                     if( !parentDesc.IsEmpty() )
                         desc = wxString::Format( wxT( "%s (%s)" ), parentDesc, lib );
 
+                    UTF8 utf8Lib( lib );
+
                     std::vector<LIB_SYMBOL*> symbols;
 
                     std::copy_if( libSymbols.begin(), libSymbols.end(),
                                   std::back_inserter( symbols ),
-                                  [&lib]( LIB_SYMBOL* aSym )
+                                  [&utf8Lib]( LIB_SYMBOL* aSym )
                                   {
-                                      return lib.IsSameAs( aSym->GetLibId().GetSubLibraryName() );
+                                      return utf8Lib == aSym->GetLibId().GetSubLibraryName();
                                   } );
 
                     addFunc( name, symbols, desc );
diff --git a/include/database/database_lib_settings.h b/include/database/database_lib_settings.h
index 06de70ce49..c090011476 100644
--- a/include/database/database_lib_settings.h
+++ b/include/database/database_lib_settings.h
@@ -22,6 +22,7 @@
 #define KICAD_DATABASE_LIB_SETTINGS_H
 
 #include <settings/json_settings.h>
+#include <wx/string.h>
 
 
 enum class DATABASE_SOURCE_TYPE
@@ -44,12 +45,17 @@ struct DATABASE_SOURCE
 
 struct DATABASE_FIELD_MAPPING
 {
-    std::string column;              ///< Database column name
-    std::string name;                ///< KiCad field name
-    bool        visible_on_add;      ///< Whether to show the field when placing the symbol
-    bool        visible_in_chooser;  ///< Whether the column is shown by default in the chooser
-    bool        show_name;           ///< Whether or not to show the field name as well as its value
-    bool        inherit_properties;  ///< Whether or not to inherit properties from symbol field
+    const std::string column;             ///< Database column name
+    const std::string name;               ///< KiCad field name
+    const wxString    name_wx;            ///< KiCad field name (converted)
+    const bool        visible_on_add;     ///< Whether to show the field when placing the symbol
+    const bool        visible_in_chooser; ///< Whether the column is shown by default in the chooser
+    const bool        show_name;   ///< Whether or not to show the field name as well as its value
+    const bool inherit_properties; ///< Whether or not to inherit properties from symbol field
+
+    explicit DATABASE_FIELD_MAPPING( std::string aColumn, std::string aName, bool aVisibleOnAdd,
+                                     bool aVisibleInChooser, bool aShowName,
+                                     bool aInheritProperties );
 };