Página 1 de 1

Chamando procedure SQL

Enviado: 04 Set 2021 18:51
por JoséQuintas
Tava aqui pensando.... como integrar melhor as stored procedures com o Harbour?

Código: Selecionar todos

   :ExecuteCmd( "call ze_jptabcategoriaLicencaExclui(" + NumberSQL( nIdCategoria ) + "," + NumberSQL( nIdLicenca ) + ")" )
Depois pensei.... porque não uma função intermediária?

Código: Selecionar todos

ze_TabCategoriaLicencaExclui( nIdCategoria, nIdLicenca )
...
FUNCTION ze_TabCategoriaLicencaExclui( nIdCategoria, nIdLicenca )
   :ExecuteCmd( "call ze_jptabcategoriaLicencaExclui(" + NumberSQL( nIdCategoria ) + "," + NumberSQL( nIdLicenca ) + ")" )
   RETURN Nil
Mas vai ter muito criar conexão ou algo parecido.

Código: Selecionar todos

FUNCTION ExecuteSQLProcedure( ... )

   LOCAL cnSQL := ADOClass():New( AppConexao() )
   LOCAL cSQL, aList

   aList := hb_AParams()
   // monta a chamada de SQL e execute
   ...
Não valida o nome da procedure? mas... também não valida o texto do comando SQL, então dá no mesmo
Pode até servir para casos com e sem retorno.

Apesar de parecer quase a mesma coisa, fica melhor para o fonte.

Código: Selecionar todos

   :ExecuteCmd( "call ze_jptabcategoriaLicencaExclui(" + NumberSQL( nIdCategoria ) + "," + NumberSQL( nIdLicenca ) + ")" )

Código: Selecionar todos

ExecuteSQLProcedure( "ze_jptabcategoriaLicencaExclui", nIdCategoria, nIdLicenca )
A função de executar procedure faria a conversão dos parâmetros, conforme o tipo.
Fonte mais limpo.

Vou amadurecer essa idéia.
Dá até pra validar o nome das procedures, pra ver se existem mesmo
Um campo array STATIC, assim numa checagem seguinte basta olhar se está no array.

Chamando procedure SQL

Enviado: 04 Set 2021 19:34
por JoséQuintas
Nessas horas dá um nó na cabeça.

Seria melhor se o banco de dados tivesse uma API de acesso direto as procedures/functions?
Mas aí o SQL cai por terra.... seria melhor um objeto.

Mas o objeto cai por terra, quando lembramos que as IDEs para o Harbour não validam objetos.

É de ficar doido, mas são possibilidades... é disso que nascem novas opções.

Chamando procedure SQL

Enviado: 05 Set 2021 04:42
por JoséQuintas

Código: Selecionar todos

   cnSQL:ExecuteProcedure( "ze_PedidoCalculo", nIdPedido )

   //WITH OBJECT cnSQL
      //cnSQL:ExecuteCmd( "CALL ze_PedidoCalculo(" + NumberSQL( nIdPedido ) + ")" )
   //ENDWITH
Coloquei na classe ADO e vamos em frente.

Chamando procedure SQL

Enviado: 05 Set 2021 07:48
por JoséQuintas
Esta com mais parâmetros;

Código: Selecionar todos

   cnSQL:ExecuteProcedure( "ze_PedidoProdutoBaixaEstoque", nIdItPed, dData, ;
         nNumNotFis, cDeposito, nSomaTira, LogInfo() )

   WITH OBJECT cnSQL
      :Execute( "CALL ze_PedidoProdutoBaixaEstoque( " + ;
         NumberSQL( nIdItPed ) + ", " + DateSQL( dData ) + ", " + ;
         NumberSQL( nNumNotFis ) + ", " + StringSQL( cDeposito ) + ", " + ;
         NumberSQL( nSomaTira ) + ", " + StringSQL( LogInfo() ) + ")" )
   ENDWITH
Deixei execute, porque no resto está execute, mas pensei em CallProcedure, ou somente :Call

Chamando procedure SQL

Enviado: 05 Set 2021 16:10
por JoséQuintas
Acabei alterando, pra ter os mesmos recursos que já tenho.

Código: Selecionar todos

METHOD ExecuteCmdProcedure( ... ) CLASS ADOClass

   LOCAL cSQL, aItem, aList := hb_AParams()

   cSQL := "CALL " + aList[ 1 ]
   hb_ADel( aList, 1, .T. )

   cSQL += "("
   FOR EACH aItem IN aList
      cSQL += ValueSQL( aItem )
      cSQL += iif( aItem:__ENumIsLast(), "", "," )
   NEXT
   cSQL += ")"
   ::ExecuteCmd( cSQL )

   RETURN Nil

METHOD ExecuteProcedure( ... ) CLASS ADOClass

   LOCAL cSQL, aItem, aList := hb_AParams()

   cSQL := "CALL " + aList[ 1 ]
   hb_ADel( aList, 1, .T. )

   cSQL += "("
   FOR EACH aItem IN aList
      cSQL += ValueSQL( aItem )
      cSQL += iif( aItem:__ENumIsLast(), "", "," )
   NEXT
   cSQL += ")"
   ::Execute( cSQL )

   RETURN Nil
Hoje tenho Execute() e ExecuteCmd()
Uma considera o recordset principal, e a outra cria um alternativo.
Então fiz igual pra procedure, porque em alguns casos, ela não deve interferir no recordset principal.

Tipo....

Código: Selecionar todos

WITH OBJECT cnSQL
   :Execute( "comando" )
   DO WHILE ! :Eof()
      :ExecuteCmd( "ddddd" )
      :MoveNext()
   ENDDO
   :CloseRecordset()
END WITH
No caso acima, o :ExecuteCmd() não causa interferência no recordset que já está aberto.
Apesar do nome, ela pode retornar recordset, mas independente do que já está em uso.

Lembrando: eu misturo conexão e recordset, numa única classe, pra facilitar.

Chamando procedure SQL

Enviado: 05 Set 2021 16:28
por JoséQuintas
stored.png
Parece até que o MySQL ficou integrado ao aplicativo, dispensando conversões.
Mas só parece, continua tudo igual antes.

Chamando procedure SQL

Enviado: 05 Set 2021 16:33
por JoséQuintas
O :Execute() da imagem anterior, esqueci de apagar.

Chamando procedure SQL

Enviado: 08 Set 2021 06:50
por JoséQuintas
Aqui mais interessante.

Fonte anterior Harbour:

Código: Selecionar todos

      WITH OBJECT cnSQL
         :cSQL := "SELECT * FROM JPITPED WHERE IPPEDIDO = " + NumberSQL( nIdPedidoJuntar )
         :Execute()
         DO WHILE ! :Eof()
            IF ADORecCount( "JPITPED", "IPPEDIDO = " + NumberSQL( nIdPedido ) + " AND IPPRODUTO = " + NumberSQL( :Number( "IPPRODUTO" ) ) ) == 0
               :QueryCreate()
               :QueryAdd( "IPPEDIDO", StrZero( nIdPedido, 6 ) )
               :QueryAdd( "IPPRODUTO", StrZero( :Number( "IPPRODUTO" ), 6 ) )
               :QueryAdd( "IPQTDE", :Number( "IPQTDE" ) )
               :QueryExecuteInsert( "JPITPED" )
            ELSE
               :ExecuteCmd( "UPDATE JPITPED SET IPQTDE = IPQTDE + " + NumberSQL( :Number( "IPQTDE" ) ) + ;
                  " WHERE IPPEDIDO = " + NumberSQL( nIdPedido ) )
            ENDIF
            :MoveNext()
         ENDDO
         :CloseRecordset()
      ENDWITH
fonte atual:

Código: Selecionar todos

      cnSQL:ExecuteCmdProcedure( "ze_PedidoJuntar", nIdPedido, nIdPedidoJuntar )
procedure:

Código: Selecionar todos

CREATE PROCEDURE ze_PedidoJuntar( nIdPedido INT(11), nIdPedidoJuntar INT(11) )

BEGIN

DECLARE nIdProduto INT(11);
DECLARE nQtde, nPrePed DECIMAL(16,4);

DECLARE nCursorEOF INT(11) DEFAULT 0;
DECLARE SP_CURSOR CURSOR FOR
   SELECT IPPRODUTO, IPQTDE, IPPREPED
   FROM JPITPED
   WHERE IPPEDIDO = nIdPedidoJuntar;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET nCursorEOF = 1;

OPEN SP_CURSOR;

THIS:WHILE nCursorEOF <> 1 DO
   FETCH SP_CURSOR INTO nIdProduto, nQtde, nPrePed;
   IF nCursorEOF = 1 THEN
      LEAVE THIS;
   END IF;
   IF ( SELECT COUNT(*) FROM JPITPED WHERE IPPEDIDO = nIdPedido AND IPPRODUTO = nIdProduto ) != 0 THEN
      UPDATE JPITPED SET IPQTDE = IPQTDE + nQtde WHERE IPPEDIDO = nIdPedido AND IPPRODUTO = nIdProduto;
   ELSE
      INSERT
      INTO JPITPED ( IPPEDIDO, IPPRODUTO, IPQTDE, IPPREPED )
      VALUES ( nIdPedido, nIdProduto, nQtde, nPrePed );
   END IF;
END WHILE;

CLOSE SP_CURSOR;

END
Coloquei pra gravar o valor, mas vou repensar.
O problema seria permitir um preço não autorizado.

Chamando procedure SQL

Enviado: 08 Set 2021 14:56
por JoséQuintas
Mais outro.

Era assim em Harbour:

Código: Selecionar todos

         WITH OBJECT cnSQL
            :ExecuteCmdProcedure( "ze_PedidoRelaciona", nIdPedido, nIdPedidoRel, ::cOpc )
/*
            IF nIdPedidoRel == 0
               :QueryCreate()
               :QueryAdd( "PDPEDREL", StrZero( 0, 6 ) )
               :QueryAdd( "PDNOTREL", StrZero( 0, 9 ) )
               :QueryExecuteUpdate( "JPPEDIDO", "IDPEDIDO = " + NumberSQL( nIdPedido ) )
            ELSE
               :cSQL := "SELECT JPPEDIDO.*, JPITPED.*, JPNOTFIS.NFNOTFIS" + ;
                  " FROM JPPEDIDO" + ;
                  " LEFT JOIN JPITPED ON JPITPED.IPPEDIDO = JPPEDIDO.IDPEDIDO" + ;
                  " LEFT JOIN JPNOTFIS ON JPNOTFIS.NFPEDIDO = JPPEDIDO.IDPEDIDO" + ;
                  " WHERE IDPEDIDO = " + NumberSQL( nIdPedidoRel )
               :Execute()
               IF :Eof()
                  :QueryCreate()
                  :QueryAdd( "PDPEDREL", StrZero( 0, 6 ) )
                  :QueryAdd( "PDNOTREL", StrZero( 0, 9 ) )
                  :QueryExecuteUpdate( "JPPEDIDO", "IDPEDIDO = " + NumberSQL( nIdPedido ) )
               ELSE
                  :QueryCreate()
                  :QueryAdd( "PDPEDREL", StrZero( nIdPedidoRel, 6 ) )
                  :QueryAdd( "PDNOTREL", StrZero( ADOField( "NFNOTFIS", "N", "JPNOTFIS", "NFPEDIDO = " + NumberSQL( nIdPedidoRel ) ), 9 ) )
                  :QueryExecuteUpdate( "JPPEDIDO", "IDPEDIDO=" + NumberSQL( nIdPedido ) )
                  IF ::cOpc == "I"
                     :QueryCreate()
                     :QueryAdd( "PDVALSEG", :Number( "PDVALSEG" ) )
                     :QueryAdd( "PDVALOUT", :Number( "PDVALOUT" ) )
                     :QueryAdd( "PDVALEXT", :Number( "PDVALEXT" ) )
                     :QueryAdd( "PDVALFRE", :Number( "PDVALFRE" ) )
                     :QueryAdd( "PDVALDES", :Number( "PDVALDES" ) )
                     :QueryExecuteUpdate( "JPPEDIDO", "IDPEDIDO = " + NumberSQL( nIdPedido ) )
                     DO WHILE ! :Eof()
                        :QueryCreate()
                        :QueryAdd( "IPPEDIDO", StrZero( nIdPedido, 6 ) )
                        FOR EACH cField IN { "IPPRODUTO", "IPTRIBUT" }
                           :QueryAdd( cField, StrZero( :Number( cField ), 6 ) )
                        NEXT
                        FOR EACH cField IN { "IPCFOP", "IPPEDCOM", "IPLEIS", "IPORIGEM", "IPIPIICM", ;
                              "IPIPICST", "IPIPIENQ", "IPICMCST", "IPDIFCAL", "IPPISCST", "IPPISENQ", ;
                              "IPCOFCST", "IPCOFENQ" }
                           :QueryAdd( cField, :String( cField ) )
                        NEXT
                        FOR EACH cField IN { "IPPRECUS", "IPPREPED", "IPQTDE", "IPVALCUS", "IPGARANTIA", ;
                              "IPPRENOT", "IPVALADI", "IPVALFRE", "IPVALSEG", "IPVALOUT", "IPVALEXT", ;
                              "IPVALADU", "IPVALIOF", "IPVALDES", "IPVALPRO", "IPVALNOT", "IPIIBAS", ;
                              "IPIIALI", "IPIIVAL", "IPIPIBAS", "IPIPIALI", "IPIPIVAL", "IPICMBAS", ;
                              "IPICMALI", "IPICMRED", "IPICMVAL", "IPFCPALI", "IPFCPVAL", "IPICSBAS", ;
                              "IPICSALI", "IPICSVAL", "IPSUBIVA", "IPSUBBAS", "IPSUBRED", "IPSUBALI", ;
                              "IPSUBVAL", "IPDIFBAS", "IPDIFALIF", "IPDIFALIU", "IPDIFALII", "IPDIFVALI", ;
                              "IPDIFVALF", "IPPISBAS", "IPPISALI", "IPPISVAL", "IPCOFBAS", "IPCOFALI", ;
                              "IPCOFVAL", "IPISSBAS", "IPISSALI", "IPISSVAL" }
                           :QueryAdd( cField, :Number( cField ) )
                        NEXT
                        :QueryExecuteInsert( "JPITPED" )
                        :MoveNext()
                     ENDDO
                  ENDIF
               ENDIF
               :CloseRecordset()
            ENDIF
            SubPedidoClass():CalculaValores( nIdPedido )
*/
            :ExecuteCmdProcedure( "ze_PedidoCalculo", nIdPedido )
         ENDWITH
Agora fica no servidor, assim em SQL

Código: Selecionar todos

CREATE PROCEDURE ze_PedidoRelaciona( nIdPedido INT(11), nIdPedidoRel INT(11), cOpcao VARCHAR(5) )

THIS:BEGIN

IF nIdPedidoRel = 0 THEN
   UPDATE
   JPPEDIDO SET
   PDPEDREL = '000000', PDNOTREL = '000000000'
   WHERE IDPEDIDO = nIdPedido;
   LEAVE THIS;
END IF;

IF ( SELECT IDPEDIDO FROM JPPEDIDO WHERE IDPEDIDO = nIdPedidoRel ) = 0 THEN
   UPDATE
   JPPEDIDO SET
   PDPEDREL = '000000', PDNOTREL = '000000000'
   WHERE IDPEDIDO = nIdPedido;
   LEAVE THIS;
END IF;

UPDATE
JPPEDIDO SET
PDPEDREL = LPAD( nIdPedidoRel, 6, '0' ),
PDNOTFIS = LPAD( COALESCE( ( SELECT NFPEDIDO FROM JPNOTFIS WHERE NFPEDIDO = nIdPedidoRel ), 0 ), 9, '0' )
WHERE IDPEDIDO = nIdPedido;

IF cOpcao != "I" THEN
   LEAVE THIS;
END IF;

UPDATE
JPPEDIDO
INNER JOIN JPPEDIDO AS B ON B.IDPEDIDO = nIdPedidoRel
SET
JPPEDIDO.PDVALSEG = COALESCE( B.PDVALSEG, 0 ),
JPPEDIDO.PDVALOUT = COALESCE( B.PDVALOUT, 0 ),
JPPEDIDO.PDVALEXT = COALESCE( B.PDVALEXT, 0 ),
JPPEDIDO.PDVALFRE = COALESCE( B.PDVALFRE, 0 ),
JPPEDIDO.PDVALDES = COALESCE( B.PDVALDES, 0 )
WHERE JPPEDIDO.IDPEDIDO = nIdPedido;

INSERT
INTO JPITPED
( IPPEDIDO, IPPRODUTO, IPTRIBUT,
IPCFOP, IPPEDCOM, IPLEIS, IPORIGEM, IPIPIICM,
IPIPICST, IPIPIENQ, IPICMCST, IPDIFCAL, IPPISCST, IPPISENQ,
IPCOFCST, IPCOFENQ,
IPPRECUS, IPPREPED, IPQTDE, IPVALCUS, IPGARANTIA,
IPPRENOT, IPVALADI, IPVALFRE, IPVALSEG, IPVALOUT, IPVALEXT,
IPVALADU, IPVALIOF, IPVALDES, IPVALPRO, IPVALNOT, IPIIBAS,
IPIIALI, IPIIVAL, IPIPIBAS, IPIPIALI, IPIPIVAL, IPICMBAS,
IPICMALI, IPICMRED, IPICMVAL, IPFCPALI, IPFCPVAL, IPICSBAS,
IPICSALI, IPICSVAL, IPSUBIVA, IPSUBBAS, IPSUBRED, IPSUBALI,
IPSUBVAL, IPDIFBAS, IPDIFALIF, IPDIFALIU, IPDIFALII, IPDIFVALI,
IPDIFVALF, IPPISBAS, IPPISALI, IPPISVAL, IPCOFBAS, IPCOFALI,
IPCOFVAL, IPISSBAS, IPISSALI, IPISSVAL )
SELECT
nIdPedido, IPPRODUTO, IPTRIBUT,
IPCFOP, IPPEDCOM, IPLEIS, IPORIGEM, IPIPIICM,
IPIPICST, IPIPIENQ, IPICMCST, IPDIFCAL, IPPISCST, IPPISENQ,
IPCOFCST, IPCOFENQ,
IPPRECUS, IPPREPED, IPQTDE, IPVALCUS, IPGARANTIA,
IPPRENOT, IPVALADI, IPVALFRE, IPVALSEG, IPVALOUT, IPVALEXT,
IPVALADU, IPVALIOF, IPVALDES, IPVALPRO, IPVALNOT, IPIIBAS,
IPIIALI, IPIIVAL, IPIPIBAS, IPIPIALI, IPIPIVAL, IPICMBAS,
IPICMALI, IPICMRED, IPICMVAL, IPFCPALI, IPFCPVAL, IPICSBAS,
IPICSALI, IPICSVAL, IPSUBIVA, IPSUBBAS, IPSUBRED, IPSUBALI,
IPSUBVAL, IPDIFBAS, IPDIFALIF, IPDIFALIU, IPDIFALII, IPDIFVALI,
IPDIFVALF, IPPISBAS, IPPISALI, IPPISVAL, IPCOFBAS, IPCOFALI,
IPCOFVAL, IPISSBAS, IPISSALI, IPISSVAL
FROM JPITPED
WHERE IPPEDIDO = nIdPedidoRel;

END
Fonte final Harbour:

Código: Selecionar todos

         WITH OBJECT cnSQL
            :ExecuteCmdProcedure( "ze_PedidoRelaciona", nIdPedido, nIdPedidoRel, ::cOpc )
            :ExecuteCmdProcedure( "ze_PedidoCalculo", nIdPedido )
         ENDWITH