Você está na página 1de 6

Abrangência

Versão 8.11

O objetivo do Embedded SQL é facilitar a escrita e leitura de query's. Foi definida uma
sintaxe para que se possa escrever a query diretamente no código ADVPL, sem a
necessidade de ficar concatenando pedaços de string para compor a string final.

Disponibilidade do Recurso

Este recurso está disponível apenas no Protheus 8. A utilização do Embedded


SQL divide-se em : compilação do fonte, e execução do fonte. Para ser possível compilar
um fonte com o código escrito no formato Embedded, deve ser utilizado um Protheus, com
Build igual ou superior a 7.00.050721p, em um ambiente com repositório para TopConnect
( RPODB=TOP ).

Para a execução deste código-fonte, é necessária a aplicação de um patch para o


ambiente, disponível nos links abaixo :

Path - LIB 811 EmbeddedSql - Português


Path - LIB 811 EmbeddedSql - Espanhol
Path - LIB 811 EmbeddedSql - Inglês

A partir da atualização da LIB 811, superior a 'Lib 20050902 - 811', não será necessária
a aplicação deste patch.
Exemplo básico - Fonte atual

cQuery : 'SELECT SE2.E2_PREFIXO,SE2.E2_NUM '


cQuery += 'FROM '+RetSqlTable('SE2')+' SE2,'+RetSqlTable('QEK')+' QEK '
cQuery += 'WHERE SE2.E2_FILIAL= '+xfilial('SE2')+' AND '
cQuery += 'SE2.E2_PREFIXO<> ''+cPrefixo+'' AND '
cQuery += 'SE2.D_E_L_E_T_ = ' ' '
cQuery += 'ORDER BY '+RetSqlOrder('SE2')

dbUseArea(.T.,'TOPCONN',TcGenQry(,,cQuery),'E2TEMP',.T.,.T.)

TCSetField('E2TEMP','E2_EMISSAO','D',8,0)

Exemplo básico - Utilizando Embedded SQL

BeginSql alias 'E2TEMP'


column E2_EMISSAO as Date
%noparser%
SELECT SE2.E2_PREFIXO,SE2.E2_NUM
FROM %table:SE2% SE2,%table:QEK% QEK
WHERE SE2.E2_FILIAL= %xfilial:SE2% AND
SE2.E2_PREFIXO<> %exp:cPrefixo% AND
SE2.%notDel%
ORDER BY %Order:SE2%
EndSql

Características operacionais - Sintaxe

• O bloco onde será escrito o Select deve sempre ser iniciado com 'BeginSql alias' e
finalizado com 'EndSql'.
• Partes do código que devem ser substituídas aparecem entre os sinais de %. Estas
expressões possuem tratamento especial em momento de execução.
• Qualquer instrução colocada entre BEGINSQL ... ENDSQL, que não seja uma
expressão %...% , será inserida na query a ser enviada para o banco, de forma
literal.
• Variáveis, expressões, funções aparecem iniciando com %exp: %.
• Em column, especificar campos da query que são do tipo data, lógico ou numérico
(DATE, LOGIC, NUMBER). Esta linha é trocada por chamadas à função
TCSetField.
• %noparser% indica que a query não deve passar pela função 'ChangeQuery' antes
de ser enviada ao banco de dados. Caso não especificado, o default é a string da
query ser passada automaticamente pela função ChangeQuery.
• %table:<alias>% é substituída por RetSqlName(<alias>)
• %notDel% é substituída por D_E_L_E_T_= ' '
• %Order:<alias>% é substituída por SqlOrder(<alias>->(IndexKey()))

Há 3 opções para o %Order:

1. %Order: <cAlias> % traduzido para

SqlOrder(<cAlias>->(IndexKey()))

2. %Order: <cAlias>, <nIndice>% traduzido para

SqlOrder(<cAlias>->(IndexKey(<nIndice>)))

3. %Order: <cAlias>, <cNick>% traduzido para

SqlOrder(<alias>->(DBNickIndexKey(<cNick>)))

Limitação:

• Não é permitido incluir funções no meio do código 'embedded'. Se precisar, o valor


deve ser guardado em uma variável antes do início do BeginSql.

Ex:
tam_cp := GetE2ValorSize()
BeginSql alias 'E2TEMP'
column E2_EMISSAO as Date, E2_VALOR as
Numeric(tam_cp,2)
...
EndSql

Erros de Compilação

Caso seja utilizado algum argumento inválido para especificar as colunas, ou erros de
sintaxe nas expressões a serem transformadas para a montagem da query, a compilação do
fonte é interrompida com a ocorrência 'Syntax Error', informando a linha onde a primeira
ocorrência foi encontrada.

ENDSQL (Error C2001 Syntax error:)

Caso a ocorrência de compilação aponte diretamente para a linha do código-fonte, onde


está escrita a instrução EndSql, verifique se existe algum espaço em branco ou tabulação, a
partir do início da linha, antes da instrução EndSql. A versão atual desde ambiente não
suporta esta declaração, exigindo que a instrução EndSql seja alinhada à esquerda do fonte,
sem espaços ou tabulações.
Erros de Execução

• 'Query Argument Error : Alias [XXX] already in use.'

Caso a instrução BeginSQL especifique um alias que já esteja aberto (em uso), a
aplicação é abortada com a ocorrência de erro fatal acima, informando em XXX o
alias utilizado.
• 'Query Argument Error : Invalid Value Type [X]'

Caso alguma expressão informada na Query, através da tag %exp: ... %, retorne um
valor de tipo diferente de 'C' Catacter, 'D' Data, 'N' Numérico, ou 'L' Lógico, a
aplicação é abortada com a ocorrência de erro acima, onde o tipo do argumento
inesperado é mostrado em [X].
• 'Type Mismach on +'

Esta ocorrência, se reproduzida, informará na pilha de chamadas o número da linha


do código-fonte correspondente à instrução EndSQL. Ocorre caso alguma função
intermediária do engine do Embedded SQL, excluindo-se as funções especificadas
na query com a sintaxe %exp: ... % , retornar um conteúdo não-caractere a ser
acrescentado na Query. Esta ocorrência é de mais difícil localização, sendo útil
nestes casos a análise do arquivo temporário gerado pelo Protheus IDE, no
momento da compilação.
• Help NOFUNCW - Função __EXECSQL

Caso um fonte com o Embedded SQL seja executado em um repositório que não
tenha sido atualizado, OU que não seja um Repositório para o ambiente
TOPConnect ( RPODB=TOP), a aplicação exibirá a ocorrência acima, indicando
que a função interna de execução da Query não está presente no ambiente. Verifique
se a lib está atualizada, e se o RPO em uso é de um ambiente TOPConnect.

Características operacionais - depuração

Dada a montagem da Query, não é possível depurar o bloco do código-fonte


compreendido entre as instruções BeginSql e EndSql, não sendo considerados pontos de
parada de depuração ( BreakPoints ), caso colocados neste intervalo do código. A
colocação de pontos de parada deve ser realizada antes ou depois deste bloco.

Função auxiliar - GETLastQuery()

Após a abertura do cursor, no alias especificado, a função GetLastQuery() retorna um


array, com 5 elementos, onde estão disponíveis as seguintes informações sobre a Query
executada :

[1] cAlias - Alias usado para abrir o Cursor.


[2] cQuery - Query executada.
[3] aCampos - Array de campos com critério de conversão especificados.
[4] lNoParser - Caso .T., não foi utilizada ChangeQuery() na String original.
[5] nTimeSpend - Tempo, em segundos, utilizado para a abertura do Cursor.

Exemplo mais completo

ADVPL

BeginSql alias 'E2TEMP'


column E2_EMISSAO as Date, E2_VALOR as Numeric(tam_cp,2)
column QEK_SKLDOC As Logical

%noparser%

SELECT SE2.E2_PREFIXO,SE2.E2_NUM, SE2.E2_FORNECE,


SE2.E2_LOJA,SE2.E2_VALOR, SE2.D_E_L_E_T_ DEL1, QEK.D_E_L_E_T_ DEL2 ,
QEK.QEK_SKLDOC, SE2.R_E_C_N_O_ SE2RECNO
FROM %table:SE2% SE2,%table:qeK% QEK
WHERE SE2.E2_FILIAL= %xfilial:SE2% AND
qek.%notDel% and
SE2.E2_PREFIXO<> %exp:cPrefixo% AND
SE2.E2_NUM<> %exp:(cAlias)->M0_CODIGO% AND
SE2.E2_NUM<>45 AND
SE2.E2_FORNECE=%exp:Space(Len(SE2->E2_FORNECE))% AND
SE2.E2_EMISSAO<>%exp:MV_PAR06% AND
SE2.E2_LOJA<>%exp:MV_PAR05% AND
SE2.E2_VALOR<>%exp:MV_PAR04% AND
qek.QEK_SKLDOC<>%exp:MV_PAR03% And
SE2.%notDel%
ORDER BY %Order:SE2,1%
EndSql

Fonte gerado pelo pré-compilador (PPO)

__execSql('E2TEMP',' SELECT SE2.E2_PREFIXO,SE2.E2_NUM, SE2.E2_FORNECE,


SE2.E2_LOJA,SE2.E2_VALOR, SE2.D_E_L_E_T_ DEL1, QEK.D_E_L_E_T_ DEL2 ,
QEK.QEK_SKLDOC, SE2.R_E_C_N_O_ SE2RECNO FROM '+RetSqlName('SE2')+'
SE2, '+RetSqlName('QEK')+' QEK WHERE SE2.E2_FILIAL= '' +xFilial('SE2')+'' AND
qek.D_E_L_E_T_= ' ' and SE2.E2_PREFIXO<> '+___SQLGetValue(CPREFIXO)+' AND
SE2.E2_NUM<> '+___SQLGetValue((CALIAS)->M0_CODIGO)+' AND
SE2.E2_NUM<>45 AND SE2.E2_FORNECE= '+___SQLGetValue(SPACE(LEN(SE2-
>E2_FORNECE)))+' AND SE2.E2_EMISSAO<> '+___SQLGetValue(MV_PAR06)+'
AND SE2.E2_LOJA<> '+___SQLGetValue(MV_PAR05)+' AND SE2.E2_VALOR<>
'+___SQLGetValue(MV_PAR04)+' AND qek.QEK_SKLDOC<>
'+___SQLGetValue(MV_PAR03)+' And SE2.D_E_L_E_T_= ' ' ORDER BY '+
SqlOrder(SE2->(IndexKey(1))),{{'E2_EMISSAO','D',8,0},{'E2_VALOR','N',tam_cp,2},
{'QEK_SKLDOC','L',1,0}},.T.)