Diferencia entre cursores generados desde dbf y desde un motor externo

155 views
Skip to first unread message

Ultraton500

unread,
Jan 23, 2015, 6:49:48 PM1/23/15
to publice...@googlegroups.com
Buenas a todos, sigo con la migración de dbf a Firebird y en esta oportunidad me sucede algo que no esperaba.
En un grid muestro el resultado de una consulta cuyo 1er. campo es numérico de 1 dígito y se muestra en el grid con un checkbox para marcar los registros a procesar.
Antes de procesar los registros verifico la cantidad de tildados con SELECT count(marca1) FROM cursor WHERE marca1=1.
El problema es que al tildar un checkbox el SELECT count() no lo toma en cuenta hasta que el puntero se mueva del registro tildado. Curiosamente esto sucede si el cursor es obtenido de Firebird y no sucede si es obtenido de una .dbf.
Es decir, si tildo un registro, el SELECT count() me devuelve 0, si tildo dos me devuelve 1, etc. a menos que antes de hacer el SELECT count() mueva el puntero. Por eso puedo solucionarlo anteponiendo estas tres líneas al SELECT pero considero que no es una buena práctica.

lnRegActual=RECNO("cur_CotizacionesAExportar")
SELECT cur_CotizacionesAExportar
GO lnRegActual


Alguien tiene alguna idea de cómo evitar este comportamiento?
Como siempre muy agradecido por sus comentarios.

Saludos cordiales,
Javier.

HernanCano

unread,
Jan 23, 2015, 10:37:55 PM1/23/15
to publice...@googlegroups.com
El hecho de que sólo pase en el cursor traído de FireBird suena extraño.

Te recomiendo que hagas lo sgte:

En el InteractiveChange del CheckBox haz lo sgte:

** InterActivechange **
local lnRegActual
lnRegActual = RECNO("cur_CotizacionesAExportar")
calculate count() for cur_CotizacionesAExportar.MARCA1=1 in cur_CotizacionesAExportar to M.nTotal
go lnRegActual in cur_CotizacionesAExportar
=MessageBox("Se encontraron "+transform(M.nTotal)+" registros.")
**

Supongo que cur_CotizacionesAExportar es el cursor al que está conectado el ControlSource del CheckBox.

Ultraton500

unread,
Jan 24, 2015, 12:43:11 AM1/24/15
to publice...@googlegroups.com
Es muuuy extraño Hernan, pero lo pruebo una y otra vez y este comportamiento aparece o no según de dónde se obtenga el cursor. Es mas... hice lo siguiente: luego de obtener el cursor de Firebird agregué la línea

SELECT * FROM cur_CotizacionesAExportar INTO CURSOR cur_CotizacionesAExportar READWRITE

y así el SELECT count() funciona normalmente.

Lo que probé fue usar CALCULATE CNT() en lugar del SELECT count() y comprobé que cuenta bien la cantidad de registros marcados sin necesidad de mover el puntero. Al menos con esto ya tengo una mejor solución que la anterior.
En cuanto al código que me indicas, lo probé pero cuenta uno menos. Si tildo un registro me muestra 0, si tildo dos me muestra 1, etc.

Agradezco tu ayuda Hernan y te mando un saludo.
Javier.

mpulla

unread,
Jan 24, 2015, 12:30:57 PM1/24/15
to publice...@googlegroups.com
Hola Ultraton500

Para mi no tienen diferencia.

Que configuracion tiene el buffers de tu cursor?

Prueba
SELECT count(marca1) FROM cursor WITH (buffering = .T.)  WHERE marca1=1

Saludos.
Mauricio

Ultraton500

unread,
Jan 24, 2015, 3:08:34 PM1/24/15
to publice...@googlegroups.com
Hola Mauricio, tal como indicas se trata del buffering. 
La línea CURSORGETPROP("Buffering","cusor") me devuelve:

1 (El almacenamiento de filas y tablas en búfer está desactivado). Esto ocurre si la consulta se hace directamente a las dbf.
3 (El almacenamiento optimista de filas en búfer está activado). Esto ocurre si la consulta se hace con SQLExec o mediante FoxyDB a Firebid.

Intento encontrar la forma de establecer el buffer desactivado en toda la aplicación o al menos en la ventana.
Hasta el momento probé CURSORSETPROP("Buffering",1,"cursor")
pero me aparece el error 1597 y solo me acepta el valor 3 (que es el que quiero cambiar).

Muchas gracias por la ayuda,
Un saludo,
Javier.

HernanCano

unread,
Jan 24, 2015, 6:52:03 PM1/24/15
to publice...@googlegroups.com
Perdón, Javier.

Aclárame ésto:


>>> Lo que probé fue usar CALCULATE CNT() en lugar del SELECT count() y comprobé que cuenta bien la cantidad de registros marcados sin necesidad de mover el puntero. Al menos con esto ya tengo una mejor solución que la anterior.

>>> En cuanto al código que me indicas, lo probé pero cuenta uno menos.


Lo que te propongo: ¿cuenta bien o no?

mpulla

unread,
Jan 25, 2015, 11:35:58 AM1/25/15
to publice...@googlegroups.com
Hola Ultraton500.

Bueno aquí hay diferencia entre un cursor generado desde una dbf y otro desde una fuente externa, los de una fuente externa no se le puede apagar el buffer.

Sql siente el modo buffering por eso hay que aplicar Whit (buffering = .T.).

Para que deseas pagar el buffer?

Saludos.
Mauricio

Ultraton500

unread,
Jan 25, 2015, 2:33:04 PM1/25/15
to publice...@googlegroups.com
Hola Hernan,


>>> en cuanto a la diferencia entre CALCULATE CNT() y SELECT count() observé que:

- Si tildo el checkbox de un registro con un click y a continuación hago click en un botón que cuenta los registros tildados mediante SELECT count()... el resultado es la cantidad de tildados menos uno (a menos que antes de clickear el botón mueva el puntero del cursor).
- Si tildo el checkbox de un registro con un click y a continuación hago click en un botón que cuenta los registros tildados mediante CALCULATE CNT()... el resultado es la cantidad real de tildados (sin necesidad de mover antes el puntero del cursor).

Esto ocurre cuando el cursor fue obtenido de Firebird.
Si el cursor fue obtenido de las dbf el resultado de CALCULATE CNT() y SELECT count() es el mismo aunque el puntero no se mueva de lugar luego de tildar el checkbox.




>>> Con respecto al código que va en el InteractiveChange del checkbox dentro del grid lo que sucede es que, si no hay ningún checkbox tildado y tildo uno, el mensaje dice "Se encontraron 0 registros.". Si tildo un segundo registro el mensaje dice "Se encontraron 1 registros.". Si destildo uno de los registros tildados el mensaje dice "Se encontraron 2 registros." y así siempre me muestra la cantidad que debería haber mostrado en el click anterior.

Saludos y gracias,
Javier.

Ultraton500

unread,
Jan 25, 2015, 2:48:31 PM1/25/15
to publice...@googlegroups.com
Qué tal Mauricio,

La única razón por la cual se me ocurre apagar el buffer es porque desconozco los inconvenientes que puedan surgir con este activado y quería evitar averiguarlo. Pero bueno, si no se puede apagar el buffer a un cursor de un notor externo espero que no surjan mas inconvenientes. Es solo por eso.

Saludos y gracias,
Javier.

HernanCano

unread,
Jan 25, 2015, 11:35:26 PM1/25/15
to publice...@googlegroups.com
Javier: 
Otra vez has vuelto a repetir lo que dijiste en la primera réplica: "el código cuenta bien... pero el código cuenta uno menos...".
((Tienes un problema para expresarte, pues empiezas diciendo que "cuenta bien", pero explicas diciendo que "cuenta uno menos"... y éso no es "contar bien"))

Quiero terminar de preguntarte más bien concluyendo/entendiendo que "...el código que da Hernán cuenta mal, porque da uno menos".

Por ahora lo dejaré ahí, pues no tengo tu escenario (ni lo conozco para replicarlo). Te recomiendo que hagas lo que tú mismo dices (".... puedo solucionarlo anteponiendo estas tres líneas al SELECT...").

Si deseas, podrías intentar ésto:

Alternativa 1:
** InterActivechange **
local lnRegActual
lnRegActual = RECNO("cur_CotizacionesAExportar")
go lnRegActual in cur_CotizacionesAExportar
calculate count() for cur_CotizacionesAExportar.MARCA1=1 in cur_CotizacionesAExportar to M.nTotal
go lnRegActual in cur_CotizacionesAExportar
=MessageBox("Se encontraron "+transform(M.nTotal)+" registros.")
**

Hasta podrías cambiar la línea amarillada por la sgte:

go recno("cur_CotizacionesAExportar") in cur_CotizacionesAExportar

Alternativa 2:
** InterActivechange **
go recno('cur_CotizacionesAExportar') in cur_CotizacionesAExportar
local OldSel
OldSel = select()
select count(MARCA) from cur_CotizacionesAExportar where MARCA1=1 into cursor TEMPORAL
M.nTotal = reccount('TEMPORAL')
use
select (OldSel)
=MessageBox("Se encontraron "+transform(M.nTotal)+" registros.")
**

Ultraton500

unread,
Jan 26, 2015, 12:50:05 PM1/26/15
to publice...@googlegroups.com
Hola Hernán, refiriéndome al código que me sugeriste en un principio, en mi último post no he dicho que el código cuenta bien sino que intenté describirte qué es lo que hacía.

Si no hay ningún checkbox tildado y tildo uno, el mensaje dice "Se encontraron 0 registros.".
Si tildo un segundo registro el mensaje dice "Se encontraron 1 registros.".
Si destildo uno de los registros tildados el mensaje dice "Se encontraron 2 registros.".

Conclusión: siempre me muestra la cantidad que debería haber mostrado en el click anterior.
Para eliminar cualquier problema de expresión adjunto un pequeño video del comportamiento de la rutina original y de las Alternativas1 y 2.

Por otra parte, en donde veo ahora que no me expliqué claramente fue en mi primer respuesta a Mauricio ya que no quedó claro que el SELECT count() (que no me funcionaba bien) funciona bien al agregarle "WITH (buffering = .T.)".

Te agradezco y aprecio mucho tu interés Hernán.
Te mando un cordial saludo,
Javier
codigos_checkbox.mp4

Leboni

unread,
Jan 26, 2015, 4:05:49 PM1/26/15
to publice...@googlegroups.com
Estimado Ultrathon:

Quisiera compartirte que me sucedió algo similar pero con SQLServer. Solamente pude solucionarlo generando un nuevo cursor a partir del obtenido de SQLServer, ya que si los cambios los efectuaba en el grid con éste cursor (De SQLServer) se comportaba igual como tú describes.   Una vez asociado el nuevo cursor al recordsource del Grid fué santo remedio. Obviamente debes modificar tus rutinas para las actualizaciones correspondientes desde ése nuevo cursor.

Espero te sea de utilidad ésta experiencia.

Salu2..!

Ultraton500

unread,
Jan 26, 2015, 4:41:37 PM1/26/15
to publice...@googlegroups.com
Qué tal Leboni, así es, lo que me sugieres es una de las primeras cosas que probé y funciona tal como dices.
Gracias por la ayuda.

Saludos cordiales,
Javier.

HernanCano

unread,
Jan 26, 2015, 5:40:23 PM1/26/15
to publice...@googlegroups.com
Observo en las ayudas de VFP que la cláusula WITH BUFFERING re requiere para lo que necesitas: estás haciendo una consulta a un cursor en el InteractiveChange de un checkbox que muy probablemente no ha grabado los datos al cursor.

Además....

Antonio Meza

unread,
Jan 26, 2015, 5:53:36 PM1/26/15
to publice...@googlegroups.com
Hola Ultraton!!

El problema que veo es que estas modificando un cursor devuelto por un SqlExec, y se puede deber a dos problemas, que el código de selección lo tienes en el interactiveChange del Check y la otra que estas aplicando un Select sobre el cursor modificado con buffering.

Lo que te recomiendo es usar el evento Valid del Check y probar si ya te calcula bien, y la otra es usar mejor Calculate Cnt() para saber cuantos registros están marcados.

saludos
Antonio Meza


El lunes, 26 de enero de 2015, 11:50:05 (UTC-6), Ultraton500 escribió:

Antonio Meza

unread,
Jan 26, 2015, 6:05:39 PM1/26/15
to publice...@googlegroups.com
Se me olvidaba comentar, otra situación que te puede estar pasando, es que al cursor devuelto por SqlExec si modificas el registro este no se ve el cambio si intentas aplicar otro Select sobre ese cursor, para que el cambio se vea aplicado tendrías que moverte de registro, y entonces ya se aplicaría el cambio y puedes generar el nuevo select y muestre correctamente.

Acabo de hacer una prueba, pues recordé que en el pasado me encontré con ese detalle, ejemplo

* Aquí no muestra ningún registro
SqlExec(......,"prueba")
Select prueba
replace valor1 con 1 
select * from pruebas where valor1 = 1

* Aquí si lo muestra
SqlExec(......,"prueba")
Select prueba
replace valor1 con 1 
go top          && muevo de registro
select * from pruebas where valor1 = 1


saludos
Antonio Meza

Antonio Meza

unread,
Jan 26, 2015, 6:07:48 PM1/26/15
to publice...@googlegroups.com
Incluso puedes usar un GO RECNO() en vez del go top.

saludos

Ultraton500

unread,
Jan 27, 2015, 3:09:31 PM1/27/15
to publice...@googlegroups.com
Hernán, 
tal como dices la cláusula WITH BUFFERING es lo indicado en mi caso. Al código que me has sugerido lo coloqué en el Valid como sugiere Antonio y así si reconoce el cambio en el cursor.

Antonio,
como le comentaba a Hernán seguí tus indicaciones de mover el código al evento Valid y eso hizo que funcionara.
Yo ya había notado que los cambios se grababan en el cursor al mover el puntero de registro y por eso lo solucionaba haciendo

lnRegActual=RECNO("cursor")
SELECT cursor
GO lnRegActual

pero no sabía que funcionaría solo con GO RECNO(). Gracias por el dato.

Saludos y nuevamente gracias por sus aportes.
Javier.
Reply all
Reply to author
Forward
0 new messages