Meu uso de ADO parece ADO... mas não é
É que uso uma classe intermediária.
Até poderia alterar o ADO original da Microsoft, pelo Harbour, mas preferi assim.
O ADO tem Eof(), MoveNext(), Fields(), Move(), etc. e minha classe também, apenas não é diretamente a função do ADO.
Código: Selecionar todos
oTemporario := oConexao:Execute( "SELECT NOME FROM CLIENTES WHERE CODIGO=1" )
Se não tem nada, não retorna nada, NIL, nada mesmo, não um recordset com zero registros.
Se não tem conteúdo, como é que vai criar uma estrutura pra um retorno sem nenhum campo?
É... porque se SELECT é pra pesquisar campos diversos, como pode existir uma estrutura pré-definida pra não se sabe o que?
Pois é...
Por isso eu criei a classe temporária.
Testar EOF() em nada... não dá.
Seria algo como NIL:Eof()
Imagine em tudo que é fonte, ficar testando se o retorno é NIL, se o campo existe pra não dar erro, se tem conteúdo antes de testar EOF(), etc. etc. etc.
Complicado... então criei a classe intermediária que evita todos esses erros, e toda necessidade dessa checagem, porque ela já faz.
A classe, de certa forma, é relativamente simples: tem o recordset, e tem funções que são repassadas ao recordset.
Código: Selecionar todos
CLASS ADOClass
VAR oRecordset
METHOD Eof() INLINE ::oRecordset:Eof()
METHOD MoveNext() INLINE ::oRecordset:MoveNext()
ENDCLASS
EOF() da classe vai testar EOF() no recordset.
Como eu disse antes, se testar eof() em vazio dá erro.
Com a classe intermediária, basta eu fazer isso na classe.
Código: Selecionar todos
METHOD Eof() INLINE iif( ::oRecordset == Nil, .T., ::oRecordset:Eof() )
Outro problema: MoveNext(), que seria o SKIP do DBF, dá erro se já estiver em EOF() e tentar pular para o próximo registro.
E também dá erro se fizer no arquivo vazio (NIL).
Vai precisar de 2 testes adicionais, os mesmos do EOF() e mais um pra testar EOF().
Mas dá pra aproveitar o que já existe, de eof()
Código: Selecionar todos
METHOD MoveNext() INLINE iif( ::oRecordset:Eof(), Nil, ::oRecordset:MoveNext() )
Não vai dar erro se for Nil, também não vai dar erro se já estiver em Eof().
E por aí vai.
Foi pra isso que criei a classe intermediária, pra não precisar ficar tratando erros em tudo que é fonte.
Poderia alterar o nome de MoveNext() pra Skip(), pra ficar igual DBF, mas preferi deixar com o nome original.
Também embuti a conexão como parte da classe, mais o método Execute(), e também teste pra verificar se deu erro no execute, pegando mensagem de erro do ADO.
Por isso, quando ver fontes que eu posto, pode dar a impressão de que essa parte é tratada automaticamente pelo ADO, mas não é.
Código: Selecionar todos
cnSQL := ADOLocal() // deixei de usar ADOClass():New( AppConexao() )
WITH OBJECT cnSQL
:Execute( "SELECT CODIGO FROM CLIENTES" )
DO WHILE ! :Eof()
? :Number( "CODIGO" ), :String( "NOME" )
:MoveNext()
ENDDO
:CloseRecordset()
ENDWITH
Em ADO seria mais como isto:
Código: Selecionar todos
cnSQL := win_OleCreate( "ADODB.Connection" )
cnSQL:.....
cnSQL:Open()
oRs := cnSQL:Execute( "SELECT ..." )
WITH OBJECT oRs
DO WHILE ! oRs:Eof()
? :Fields( "CODIGO" ):Value, :Fields( "NOME" ):Value
:MoveNext()
ENDDO
:Close()
ENDWITH
cnSQL:Close()
Nesse fonte faltaria o teste de Nil, por exemplo, que minha classe intermediária acaba tornando desnecessário.
NÃO SEI o que acontece na SQLMIX num caso desses, porque provavelmente deve acontecer também, do MySQL não retornar NADA.
Apenas comentário, NÃO estou falando nada contra, apenas é um comentário de que realmente não sei como isso é tratado.
No caso do ADO dá erro, é a classe que criei que evita dar erro, ou testes que sejam colocados nos fontes.
E voltando à minha classe....
Aproveitei pra adicionar recursos, que já postei por aqui, como o :ReturnSelect( "SELECT 1" )
Isso evita muito fonte adicional.
E é por aí que a gente vai simplificando nossa vida... (ou às vezes complicando) kkkk
