sábado, 22 de febrero de 2014

HARBOUR:Acelerando al viejo SET FILTER TO


Estaba yo con mis cosas, y repasando la lista de correo de harbour, leí que alguien ponía una función, llamada OrdWildSeek

Buscando más información sobre dicha función, me percaté enseguida, que haciendo un poco de malabares y con un indice CUSTOM, y sin apenas esfuerzos, podemos quitar nuestros SET FILTER, que por su utilidad estaban, pero que por su ineficacia no lo usaba prácticamente nadie.

Cada vez que he tenido que usar un LIKE en SQL, pasa por mi memoria el SET FILTER ;-)

¿ Y cual es la idea ? El idea es usar un sub-indice a partir del índice activo.
¿ Y como funciona ?

Pues a grandes rasgos y para que todo el mundo lo entienda;

  • SET FILTER TO , recurre TODO la DBF en busca de coincidencias.
    Ah!! y lo bonito que es ver que en el filtro hay solo 2 coincidencias separadas entre si por 200MB, el salto de un registro a otro es de "reír por no llorar" ;-)
  • OrWildSeek, recurre el FICHERO NTX ACTIVO, y nos va diciendo que registro cumple con el patrón que pasamos, y ahí es donde entramos nosotros con nuestro indices CUSTOMS


Ahora lo que más nos gusta, el código fuente.

Imagina que tenemos una tabla de clientes, y tenemos varios indices, y el 4, la expresión es nombre+apellidos.

Ahora, queremos obtener el nombre de SARAH. Pero no solo los que comienzan con SARAH, eso lo podemos solucionar rápidamente con un SCOPE, si no,  que forme parte de él, como;

  • ANGIE SARAH LOWE
  • SARAH CARMONA
  • JULIA SARAH SMITH
Eso se consigue , pasando el patrón "*"+Cadena+"?"

cNombre := "SARAH"

fast_filter( "*"+ alltrim( cNombre ) + "?", 4, 22, 28 )
Browse()


Ahora, ya estaría el filtro activado basado en subindices.

/* 
 Sustituto de SET FILTER
 cExpr  
    Expresion a buscar que forme parte del indice, podemos 
    poner *Texto? , para buscar palabra que forme parte

 nOrder
    Sobre que indice activo vamos a recorrer la lista.
    Por defecto es el indice activo.

 nRow, nCol 
     Posicion fila,columna para mostrar progreso. Se ejecuta en 
     un hilo aparte

 Return: Indice anterior

*/
function fast_filter( cExpr, nOrder, nRow, nCol )
      local PantaAnt := savescreen(0,0,MaxRow(),MaxCol())
      Local p := hb_threadStart( @Pajaritos(), nRow, nCol )
      Local nIndice := OrdNumber()

      DEFAULT nOrder TO OrdNumber()

      set order to nOrder
      INDEX ON &(IndexKey()) TAG _TEMP_ TO tHarbourt ;
               CUSTOM ADDITIVE MEMORY
       
      set order to nOrder
      go top

      DO WHILE OrdWildSeek( cExpr, .T. )
         OrdKeyAdd( "_TEMP_" )
      ENDDO
      OrdSetFocus( "_TEMP_" )
       
      hb_threadTerminateAll()
      restscreen(0 ,0 ,MaxRow(), MaxCol(), PantaAnt)

return nIndice

PROCEDURE Pajaritos( nRow, nCol )
        Local pajarito := "|",n := 0
        
        DEFAULT nRow := MaxRow(), nCol := 1

        DO WHILE .T.

           do case
              case n = 1 
                   pajarito = "|" 
              case n = 2 
                   pajarito = "/" 
              case n = 3  
                   pajarito = "-" 
              case n = 4 
                   pajarito = "\" 
              Otherwise 
                   n := 0
           end case

           DispOutAt( nRow, nCol, "Generando Consulta....[ " +  pajarito +" ]" ) //, "GR+/N" )
           ThreadSleep( 500 )
           n++
       ENDDO
RETURN


Creo que la función es muy simple y no necesita más explicación, el código habla por si mismo.
Lo único es que se crea un hilo para mostrar que se está haciendo alguna cosa.

Lo ideal sería que la función OrdWildSeek tuviese un codeblock para hacer llamada e ir mostrando un progreso, pero al no tenerlo, lo he ejecutado en un hilo aparte.

He de decir que me sorprende la velocidad, eso si, siempre teniendo en cuenta la cantidad de información a recorrer, avisados estáis.

Espero que os guste ;-)