1 de diciembre de 2011

Abrir un cursor para lectura/escritura

Como sabemos, los cursores creados por el comando SELECT INTO en VFP son solo lectura. A partir de VFP 7 se incluyo una clausula llamada READWRITE que nos permite indicar si queremos que el cursor sea de lectura-escritura, lo cual es sumamente útil en infinidad de situaciones.

Sin embargo, para los que por algún motivo aun debemos seguir trabajando con versiones anteriores a VFP 6, convertir un cursor a lectura-escritura representa todo un reto. El truco mas usado para lograr esto en VFP 6 es usar la clausula NOFILTER para asegurarnos que VFP creara un cursor fisico temporal, hacer una copia fisica del cursor temporal con otro nombre, cerrar el cursor original y luego abrir el cursor temporal con el nombre original del cursor:

SELECT * FROM mitabla INTO CURSOR Q1 NOFILTER
SELECT Q1
COPY FILE (DBF("Q1")) TO ("Q1.TMP")
USE IN Q1
SELECT 0
USE ("Q1.TMP") ALIAS Q1

Pero esta solución dista mucho de ser perfecta, especialmente si el cursor original contaba con columnas cuyo nombre superara los 10 caracteres. En estos casos, el nombre de esas columnas era truncado lo cual causaba molestos problemas con las referencias a esas columnas en el código.

Hace un tiempo ayudé a un amigo a encontrar una forma de solventar este problema, y me encontré con que, como siempre, VFP me daba todas las herramientas necesarias para lograrlo; era solo cuestión de ponerlas a trabajar juntas.

En este caso, la ayuda llegó de mano de los arrays. Yo sabía desde siempre que VFP contaba con una función que tomaba la estructura de un DBF o cursor y la almacenaba en un array. Lo que no sabía es que tanto el comando CREATE CURSOR como INSERT INTO contenían la clausula FROM ARRAY.

El resultado? una función que recibe el nombre de un cursor solo-lectura y lo convierte en lectura-escritura respetando los nombres largos de columna.

Aqui les dejo la función por si les resulta útil (NOTA Nov 19: limpié y mejorpe un poco el código, ademas de corregir un problema cuando el cursor original estaba vacío).

* openForUpdate()
* Función que recibe un cursor de S/L y lo convierte en L/E respetando las columnas con nombres largos
*
* Autor: Victor Espina
*
PROCEDURE openForUpdate(pcCursor)
 *
 * Obtenemos el schema del cursor
 LOCAL ARRAY aSchema[1]
 AFIELDS(aSchema, pcCursor)
 
 * Obtenemos el contenido del cursor
 LOCAL ARRAY aRows[1]
 LOCAL nRowCount
 SELECT * FROM (pcCursor) INTO ARRAY aRows
 nRowCount = _TALLY
 
 * Cerrar el cursor original, lo recreamos como un cursor de L/E
 * y lo llenamos con los datos originales (si habia)
 SELECT (pcCursor)
 USE
 CREATE CURSOR (pcCursor) FROM ARRAY aSchema
 IF nRowCount > 0 
  INSERT INTO (pcCursor) FROM ARRAY aRows
 ENDIF
 GO TOP 
 *
ENDPROC

Victor Espina

No hay comentarios. :

Publicar un comentario