@@ -64,6 +64,7 @@ class ScrollSorter_T : public ISphMatchSorter
6464 CSphVector<CSphRowitem> m_dStatic;
6565 CSphMatchComparatorState m_tState;
6666 ScrollSettings_t m_tScroll;
67+ CSphVector<BYTE*> m_dAllocatedPtrs; // Track allocated pointer values directly
6768
6869 FORCE_INLINE bool PushMatch ( const CSphMatch & tEntry );
6970 void SetupRefMatch ();
@@ -122,8 +123,10 @@ void ScrollSorter_T<COMP>::SetupRefMatch()
122123 const ISphSchema * pSchema = m_pSorter->GetSchema ();
123124 assert (pSchema);
124125
126+ // Free old data pointer attributes before resetting
125127 FreeDataPtrAttrs ();
126- m_tRefMatch.Reset ( pSchema->GetRowSize () );
128+
129+ m_tRefMatch.Reset ( pSchema->GetDynamicSize () );
127130 m_dStatic.Resize ( pSchema->GetStaticSize () );
128131 m_tRefMatch.m_pStatic = m_dStatic.Begin ();
129132
@@ -137,11 +140,32 @@ void ScrollSorter_T<COMP>::SetupRefMatch()
137140 }
138141
139142 auto pAttr = pSchema->GetAttr ( i.m_sSortAttr .cstr () );
143+ if ( !pAttr )
144+ continue ;
145+
146+ // If the scroll token has a string type and the schema attribute is SPH_ATTR_STRING,
147+ // use the remapped STRINGPTR version (used for sorting)
148+ if ( i.m_eType ==SPH_ATTR_STRINGPTR && pAttr->m_eAttrType ==SPH_ATTR_STRING )
149+ {
150+ CSphString sRemappedName ;
151+ sRemappedName .SetSprintf ( " @int_attr_%s" , i.m_sSortAttr .cstr () );
152+ auto pRemapped = pSchema->GetAttr ( sRemappedName .cstr () );
153+ if ( pRemapped && pRemapped->m_eAttrType ==SPH_ATTR_STRINGPTR )
154+ pAttr = pRemapped;
155+ }
156+
140157 auto pRowData = pAttr->m_tLocator .m_bDynamic ? m_tRefMatch.m_pDynamic : m_dStatic.Begin ();
141158 switch ( i.m_eType )
142159 {
143160 case SPH_ATTR_STRINGPTR:
144- sphSetRowAttr ( pRowData, pAttr->m_tLocator , (SphAttr_t)sphPackPtrAttr ( { (const BYTE*)i.m_sValue .cstr (), i.m_sValue .Length () } ) );
161+ // After remapping, pAttr should be SPH_ATTR_STRINGPTR, but check to be safe
162+ if ( pAttr->m_eAttrType ==SPH_ATTR_STRINGPTR )
163+ {
164+ BYTE * pPacked = sphPackPtrAttr ( { (const BYTE*)i.m_sValue .cstr (), i.m_sValue .Length () } );
165+ sphSetRowAttr ( pRowData, pAttr->m_tLocator , (SphAttr_t)pPacked );
166+ // Track the allocated pointer value directly
167+ m_dAllocatedPtrs.Add (pPacked);
168+ }
145169 break ;
146170
147171 case SPH_ATTR_FLOAT:
@@ -158,25 +182,16 @@ void ScrollSorter_T<COMP>::SetupRefMatch()
158182template <typename COMP>
159183void ScrollSorter_T<COMP>::FreeDataPtrAttrs()
160184{
161- if ( !m_tRefMatch.m_pDynamic )
162- return ;
163-
164- const ISphSchema * pSchema = m_pSorter->GetSchema ();
165- assert (pSchema);
166-
167- for ( auto & i : m_tScroll.m_dAttrs )
185+ // Free all pointers we allocated directly
186+ // We store the pointer values themselves, not the attributes, so we don't need
187+ // to access m_tRefMatch which might have been reset
188+ for ( auto pPacked : m_dAllocatedPtrs )
168189 {
169- if ( i.m_sSortAttr ==" weight()" )
170- continue ;
171-
172- const CSphColumnInfo * pAttr = pSchema->GetAttr ( i.m_sSortAttr .cstr () );
173- assert (pAttr);
174- if ( sphIsDataPtrAttr ( pAttr->m_eAttrType ) )
175- {
176- auto pData = (BYTE *)m_tRefMatch.GetAttr ( pAttr->m_tLocator );
177- sphDeallocatePacked (pData);
178- }
190+ if ( pPacked )
191+ sphDeallocatePacked (pPacked);
179192 }
193+
194+ m_dAllocatedPtrs.Resize (0 );
180195}
181196
182197// ///////////////////////////////////////////////////////////////////
@@ -218,9 +233,22 @@ static bool CanCreateScrollSorter ( bool bMulti, const ISphSchema & tSchema, con
218233 if ( !pAttr )
219234 return false ;
220235
236+ ESphAttr eCheckType = pAttr->m_eAttrType ;
237+
238+ // If the scroll token has a string type and the schema attribute is SPH_ATTR_STRING,
239+ // check if there's a remapped STRINGPTR version (used for sorting)
240+ if ( i.m_eType ==SPH_ATTR_STRINGPTR && eCheckType==SPH_ATTR_STRING )
241+ {
242+ CSphString sRemappedName ;
243+ sRemappedName .SetSprintf ( " @int_attr_%s" , i.m_sSortAttr .cstr () );
244+ auto pRemapped = tSchema.GetAttr ( sRemappedName .cstr () );
245+ if ( pRemapped && pRemapped->m_eAttrType ==SPH_ATTR_STRINGPTR )
246+ eCheckType = SPH_ATTR_STRINGPTR;
247+ }
248+
221249 bool bSupported = false ;
222250 for ( auto eType : dSupportedTypes )
223- if ( pAttr-> m_eAttrType ==eType )
251+ if ( eCheckType ==eType )
224252 {
225253 bSupported = true ;
226254 break ;
0 commit comments