Pular para o conteúdo principal

Postagem em destaque

BlackTDN :: LeetCode :: Comparando Implementações Harbour e TLPP para o Desafio Longest Palindromic Substring

_Créditos das imagens: ChatGPT_ ### LeetCode :: Comparando Implementações Harbour e TLPP para o Desafio Longest Palindromic Substring Resolver o problema do [Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/description/) é um exercício clássico de programação, que desafia desenvolvedores a encontrar a maior substring palindrômica dentro de uma string. Recentemente, exploramos soluções tanto em Harbour quanto em TLPP (Total Language Protheus Programming). Neste artigo, comparamos as implementações nessas duas linguagens, destacando suas semelhanças, diferenças e funcionalidades específicas. #### Implementações em Harbour ##### Versão 5.1 Essa solução utiliza a técnica de expansão a partir do centro do palíndromo. Cada caractere ou par de caracteres consecutivos é considerado um possível "centro". O algoritmo expande em ambas as direções enquanto os caracteres forem iguais, retornando o maior palíndromo encontrado. ##### Versão 5....

BlackTDN :: Tips & Tricks ~ ADVPL : Embedded SQL – Tratamento de Erro

Vimos, em BlackTDN :: Tips & Tricks ~ ADVPL : Embedded SQL - Facilitador de queries,  como Embedded SQL veio para nos “facilitar” a codificação de requisições ao SGBD. Veremos, agora, como usar “Tratamento de Erro” para obter a última consulta. A exemplo do post anterior utilizarei as duas formas possíveis para a elaboração da consulta.





Query String
   1: #include "protheus.ch"
   2: #include "tbiconn.ch"
   3: #include "topconn.ch"
   4:  
   5: #xtranslate USER PROCEDURE <p> => PROCEDURE U_<p>
   6:  
   7: USER PROCEDURE NotSqlEmb()
   8:  
   9:     Local cQuery
  10:     Local cError
  11:     Local cTCSqlError
  12:  
  13:     Local cCRLF            := CRLF
  14:     Local cAlias
  15:     Local bError
  16:     Local bErrorBlock
  17:     
  18:     Local oError
  19:  
  20:     RpcSetType(3)
  21:     PREPARE ENVIRONMENT EMPRESA "01" FILIAL "01"
  22:  
  23:         bError            := { |e| oError := e , BREAK(e) }
  24:         bErrorBlock        := ErrorBlock( bError )
  25:         
  26:         cAlias            := GetNextAlias()
  27:       
  28:         BEGIN SEQUENCE
  29:  
  30:             cQuery        := "SELECT" + cCRLF
  31:             cQuery        += "    TOP 10 A1.*" + cCRLF
  32:             cQuery        += "FROM
  33:             cQuery        += "    " + RetSqlName("SA1") + " SA1 " + cCRLF
  34:             cQuery        += "WHERE" + cCRLF
  35:             cQuery        += "    SA1.D_E_L_E_T_ = ' '" + cCRLF
  36:             cQuery        += "AND" + cCRLF
  37:             cQuery        += "    SA1.A1_FILIAL = '" + xFilial("SA1") + "'" + cCRLF
  38:  
  39:             TCQUERY ( cQuery ) ALIAS ( cAlias ) NEW
  40:  
  41:             (cAlias)->( dbCloseArea() )
  42:  
  43:         RECOVER
  44:             
  45:             cError        := oError:Description
  46:             cTCSqlError    := TCSqlError()
  47:  
  48:         END SEQUENCE
  49:         ErrorBlock( bErrorBlock )
  50:  
  51:     RESET ENVIRONMENT
  52:  
  53: Return( NIL )
Embedded SQL


   1: #include "protheus.ch"
   2: #include "tbiconn.ch"
   3:  
   4: #xtranslate USER PROCEDURE <p> => PROCEDURE U_<p>
   5:  
   6: USER PROCEDURE SqlEmb()
   7:  
   8:     Local aLastQuery
   9:  
  10:     Local cQuery
  11:     Local cError
  12:     Local cTCSqlError
  13:     
  14:     Local cAlias
  15:     Local bError
  16:     Local bErrorBlock
  17:     
  18:     Local oError
  19:  
  20:     RpcSetType(3)
  21:     PREPARE ENVIRONMENT EMPRESA "01" FILIAL "01"
  22:  
  23:         bError      := { |e| oError := e , BREAK(e) }
  24:         bErrorBlock    := ErrorBlock( bError )
  25:         
  26:         cAlias      := GetNextAlias()
  27:       
  28:         BEGIN SEQUENCE
  29:  
  30:             BEGINSQL ALIAS cAlias
  31:                 %noParser%
  32:                 SELECT
  33:                     TOP 10 A1.*
  34:                 FROM
  35:                     %table:SA1% SA1
  36:                 WHERE
  37:                     SA1.%notDel%
  38:             ENDSQL
  39:  
  40:             aLastQuery    := GetLastQuery()
  41:             cLastQuery    := aLastQuery[2]
  42:  
  43:             (cAlias)->( dbCloseArea() )
  44:  
  45:         RECOVER
  46:  
  47:             aLastQuery    := GetLastQuery()
  48:             cLastQuery    := aLastQuery[2]
  49:             
  50:             cError        := oError:Description
  51:             cTCSqlError   := TCSqlError()
  52:  
  53:         END SEQUENCE
  54:         ErrorBlock( bErrorBlock )
  55:  
  56:     RESET ENVIRONMENT
  57:  
  58: Return( NIL )


Dessa forma poderemos analisar, em ambos os casos, a causa do erro.


Algo interessante sobre Embedded SQL é que ele tem uns erros “Nativos”. Por exemplo um Select * ou a ultima instrução com %xFilial:[Alias]%









Embedded SQL : Bug Select *


   1: #include "protheus.ch"
   2: #include "tbiconn.ch"
   3:  
   4: #xtranslate USER PROCEDURE <p> => PROCEDURE U_<p>
   5:  
   6: USER PROCEDURE SqlEmb()
   7:  
   8:     Local aLastQuery
   9:  
  10:     Local cQuery
  11:     Local cError
  12:     Local cTCSqlError
  13:     
  14:     Local cAlias
  15:     Local bError
  16:     Local bErrorBlock
  17:     
  18:     Local oError
  19:  
  20:     RpcSetType(3)
  21:     PREPARE ENVIRONMENT EMPRESA "01" FILIAL "01"
  22:  
  23:         bError      := { |e| oError := e , BREAK(e) }
  24:         bErrorBlock    := ErrorBlock( bError )
  25:         
  26:         cAlias      := GetNextAlias()
  27:       
  28:         BEGIN SEQUENCE
  29:  
  30:             BEGINSQL ALIAS cAlias
  31:                 %noParser%
  32:                 SELECT
  33:                     *
  34:                 FROM
  35:                     %table:SA1% SA1
  36:                 WHERE
  37:                     SA1.A1_FILIAL = %xFilial:SA1%
  38:                 AND
  39:                     SA1.%notDel%
  40:             ENDSQL
  41:  
  42:             aLastQuery    := GetLastQuery()
  43:             cLastQuery    := aLastQuery[2]
  44:  
  45:             (cAlias)->( dbCloseArea() )
  46:  
  47:         RECOVER
  48:  
  49:             aLastQuery    := GetLastQuery()
  50:             cLastQuery    := aLastQuery[2]
  51:             
  52:             cError          := oError:Description
  53:             cTCSqlError      := TCSqlError()
  54:  
  55:         END SEQUENCE
  56:         ErrorBlock( bErrorBlock )
  57:  
  58:     RESET ENVIRONMENT
  59:  
  60: Return( NIL )
O código acima fará com que Embedded SQL gere uma requisição mal formatada. Observe:





SELECT FROM  SA1010 SA1 WHERE SA1.A1_FILIAL =  '  '  AND SA1.D_E_L_E_T_= ' '

Cadê o *? Isso fará com que a requisição ao SGBD gere a seguinte exceção:






: Error : 156 (37000) (RC=-1) - [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'FROM'. ( From tMSSQLConnection::GetQueryFile )
Thread ID [980]    User [marinaldo.jesus]    IO [1837]    Tables [2]    MaxTables [3]    Comment []    Status []    SP [ ]    Traced [No]    InTran [No]    DBEnv [MSSQL/rnp]    DBThread [(SPID: 55) ]    Started [26/05/2012 15:48:18]    LastIO []    IP [127.0.0.1]    RCV [20031]    SND [54030]    TCBuild [20110919]   
SELECT FROM  SA1010 SA1 WHERE SA1.A1_FILIAL =  '  '  AND SA1.D_E_L_E_T_= ' '


Que deixará de ser emitido ao prefixarmos * com o Alias utilizado na consulta como em:






BEGINSQL ALIAS cAlias
    %noParser%
    SELECT
        SA1.*
    FROM
        %table:SA1% SA1
    WHERE
        SA1.A1_FILIAL = %xFilial:SA1%
    AND
        SA1.%notDel%
ENDSQL










Embedded SQL : Bug %xFilial:[Alias]%


   1: #include "protheus.ch"
   2: #include "tbiconn.ch"
   3:  
   4: #xtranslate USER PROCEDURE <p> => PROCEDURE U_<p>
   5:  
   6: USER PROCEDURE SqlEmb()
   7:  
   8:     Local aLastQuery
   9:  
  10:     Local cQuery
  11:     Local cError
  12:     Local cTCSqlError
  13:     
  14:     Local cAlias
  15:     Local bError
  16:     Local bErrorBlock
  17:     
  18:     Local oError
  19:  
  20:     RpcSetType(3)
  21:     PREPARE ENVIRONMENT EMPRESA "01" FILIAL "01"
  22:  
  23:         bError      := { |e| oError := e , BREAK(e) }
  24:         bErrorBlock    := ErrorBlock( bError )
  25:         
  26:         cAlias      := GetNextAlias()
  27:       
  28:         BEGIN SEQUENCE
  29:  
  30:             BEGINSQL ALIAS cAlias
  31:                 %noParser%
  32:                 SELECT
  33:                     TOP 10 SA1.*
  34:                 FROM
  35:                     %table:SA1% SA1
  36:                 WHERE
  37:                     SA1.%notDel%
  38:                 AND
  39:                     SA1.A1_FILIAL = %xFilial:SA1%
  40:             ENDSQL
  41:  
  42:             aLastQuery    := GetLastQuery()
  43:             cLastQuery    := aLastQuery[2]
  44:  
  45:             (cAlias)->( dbCloseArea() )
  46:  
  47:         RECOVER
  48:  
  49:             aLastQuery    := GetLastQuery()
  50:             cLastQuery    := aLastQuery[2]
  51:             
  52:             cError          := oError:Description
  53:             cTCSqlError      := TCSqlError()
  54:  
  55:         END SEQUENCE
  56:         ErrorBlock( bErrorBlock )
  57:  
  58:     RESET ENVIRONMENT
  59:  
  60: Return( NIL )

O código acima, em que SA1.A1_FILIAL = %xFilial:SA1% é a ultima linha da instrução SQL fará com que Embedded SQL gere uma requisição mal formatada. Observe:






SELECT TOP 10 SA1.* FROM  SA1010 SA1 WHERE SA1.D_E_L_E_T_= ' ' AND SA1.A1_FILIAL =  '  ' '


que gerará a seguinte exceção:






: Error : 105 (37000) (RC=-1) - [Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the character string ''. ( From tMSSQLConnection::GetQueryFile )
Thread ID [8852]    User [marinaldo.jesus]    IO [1837]    Tables [2]    MaxTables [3]    Comment []    Status []    SP [ ]    Traced [No]    InTran [No]    DBEnv [MSSQL/rnp]    DBThread [(SPID: 55) ]    Started [26/05/2012 15:41:02]    LastIO []    IP [127.0.0.1]    RCV [20045]    SND [54031]    TCBuild [20110919]   
SELECT TOP 10 SA1.* FROM  SA1010 SA1 WHERE SA1.D_E_L_E_T_= ' ' AND SA1.A1_FILIAL =  '  ' '


O simples fato de inverter a instrução soluciona o problema






BEGINSQL ALIAS cAlias
    %noParser%
    SELECT
        TOP 10 SA1.*
    FROM
        %table:SA1% SA1
    WHERE
        SA1.A1_FILIAL = %xFilial:SA1%
    AND
        SA1.%notDel%
ENDSQL







Esses “bugs” foram constatados na seguinte Build:

Win NT/2000

[INFO ][SERVER] [SMARTHEAP] Registering Tasks...
***  TOTVS S.A.  ***
***   www.totvs.com.br    ***
TOTVS - Build 7.00.111010P - Jan 20 2012 - 11:13:58

Acredito que em versões posteriores já estarão solucionados (ou não).


[]s
иαldσ dj

Comentários

Postagens mais visitadas