@@ -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<const CSphColumnInfo*> m_dAllocatedPtrAttrs; // Track which attributes we allocated pointers for
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,31 @@ 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+ sphSetRowAttr ( pRowData, pAttr->m_tLocator , (SphAttr_t)sphPackPtrAttr ( { (const BYTE*)i.m_sValue .cstr (), i.m_sValue .Length () } ) );
165+ // Track that we allocated a pointer for this attribute
166+ m_dAllocatedPtrAttrs.Add (pAttr);
167+ }
145168 break ;
146169
147170 case SPH_ATTR_FLOAT:
@@ -158,25 +181,26 @@ void ScrollSorter_T<COMP>::SetupRefMatch()
158181template <typename COMP>
159182void ScrollSorter_T<COMP>::FreeDataPtrAttrs()
160183{
161- if ( !m_tRefMatch.m_pDynamic )
184+ if ( !m_tRefMatch.m_pDynamic && !m_tRefMatch. m_pStatic )
162185 return ;
163186
164- const ISphSchema * pSchema = m_pSorter->GetSchema ();
165- assert (pSchema);
166-
167- for ( auto & i : m_tScroll.m_dAttrs )
187+ // Only free pointers for attributes that we actually allocated
188+ for ( auto pAttr : m_dAllocatedPtrAttrs )
168189 {
169- if ( i. m_sSortAttr == " weight() " )
190+ if ( !pAttr )
170191 continue ;
171192
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 );
193+ if ( pAttr->m_tLocator .m_bDynamic && !m_tRefMatch.m_pDynamic )
194+ continue ;
195+ if ( !pAttr->m_tLocator .m_bDynamic && !m_tRefMatch.m_pStatic )
196+ continue ;
197+
198+ auto pData = (BYTE *)m_tRefMatch.GetAttr ( pAttr->m_tLocator );
199+ if ( pData )
177200 sphDeallocatePacked (pData);
178- }
179201 }
202+
203+ m_dAllocatedPtrAttrs.Resize (0 );
180204}
181205
182206// ///////////////////////////////////////////////////////////////////
@@ -218,9 +242,22 @@ static bool CanCreateScrollSorter ( bool bMulti, const ISphSchema & tSchema, con
218242 if ( !pAttr )
219243 return false ;
220244
245+ ESphAttr eCheckType = pAttr->m_eAttrType ;
246+
247+ // If the scroll token has a string type and the schema attribute is SPH_ATTR_STRING,
248+ // check if there's a remapped STRINGPTR version (used for sorting)
249+ if ( i.m_eType ==SPH_ATTR_STRINGPTR && eCheckType==SPH_ATTR_STRING )
250+ {
251+ CSphString sRemappedName ;
252+ sRemappedName .SetSprintf ( " @int_attr_%s" , i.m_sSortAttr .cstr () );
253+ auto pRemapped = tSchema.GetAttr ( sRemappedName .cstr () );
254+ if ( pRemapped && pRemapped->m_eAttrType ==SPH_ATTR_STRINGPTR )
255+ eCheckType = SPH_ATTR_STRINGPTR;
256+ }
257+
221258 bool bSupported = false ;
222259 for ( auto eType : dSupportedTypes )
223- if ( pAttr-> m_eAttrType ==eType )
260+ if ( eCheckType ==eType )
224261 {
225262 bSupported = true ;
226263 break ;
0 commit comments