Sin embargo, para los que por algún motivo aun debemos seguir trabajando con versiones anteriores a VFP 7, 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 la 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 mejoré 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
2 comentarios:
yo uso VFP 9.0 sp2 y despues de generar el archivo.exe corre bien pero a la hora de querer agregar datos me di que el cursor es de solo lectura.....
y quisiera saber si mi problema tiene relacion con la clausula READWRITE y si es asi, como puedo hacer uso de esta clausula.
Hola, Víctor.
Te muestro otra solución. Me gustaría que me dieran su opinión al respecto.
** Testing openForUpdate...
clear
close tables all
close databases all
=MessageBox('Observa que estos dos campos tienen nombre largo';
+chr(13)+'OBSERVACION' ;
+chr(13)+'FECHA_NACIMIENTO')
create cursor PERSONAL ( CODIGO C(10), NOMBRES C(40), OBSERVACION C(40), FECHA_NACIMIENTO D )
insert into PERSONAL ( CODIGO, NOMBRES, OBSERVACION, FECHA_NACIMIENTO ) values ( "001", "ALBERTO", "Primer Registro" , {^2015.01.01} )
insert into PERSONAL ( CODIGO, NOMBRES, OBSERVACION, FECHA_NACIMIENTO ) values ( "002", "BYRON" , "Segundo Registro", {^2015.02.02} )
insert into PERSONAL ( CODIGO, NOMBRES, OBSERVACION, FECHA_NACIMIENTO ) values ( "003", "CARLOS" , "Tercer Registro" , {^2015.03.03} )
SELECT * FROM PERSONAL INTO CURSOR Q1 NOFILTER
if IsReadOnly()
=MessageBox('El cursor es de sólo lectura',0,'--primera vez--')
else
=MessageBox('El cursor es de lectura-escritura',0,'--primera vez--')
endif
=openForUpdate('q1')
PROCEDURE openForUpdate(pcCursor)
** Abrimos el cursor AGAIN en otra área, digamos con un alias "temporal"
use (dbf(pcCursor)) alias '__' in 0 again exclusive
** Cerramos el cursor "original"
use in (pcCursor)
** Nuevamente abrimos el cursor AGAIN en otra área pero con su alias original
use (dbf("__")) alias (pcCursor) in 0 again exclusive
** al abrirse EXCLUSIVE ya es de lectura y escritura...
** Cerramos el alias "temporal"
use in '__'
** Nos ubicamos en el cursor en cuestión && probablemente ésto no sea necesario............
select (pcCursor)
if IsReadOnly()
=MessageBox('El cursor es de sólo lectura',0,'--segunda vez--')
else
=MessageBox('El cursor es de lectura-escritura',0,'--segunda vez--')
endif
**
Publicar un comentario