agentleFS
replybrreplybr/plugadvpl/skills/advpl-embedded-sql/SKILL.md

advpl-embedded-sql

Skill1 starsChanged 6 months agoMITView on GitHub

SQL embarcado em ADVPL — BeginSql/EndSql, TCQuery, macros obrigatórias %notDel%, %xfilial%, %table%, %exp%, %Order%, 6 restrições de performance e segurança.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use sempre BeginSql ... EndSql para queries novas.

    line 102

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

advpl-embedded-sql — SQL nativo em ADVPL

ADVPL/TLPP suporta SQL embarcado direto no fonte com substituição por macros que garantem multi-empresa, multi-filial, anti-SQL-injection e portabilidade entre DBMS (Oracle, SQL Server, Postgres, DB2).

Existem duas formas principais:

  1. BeginSql alias <ALIAS> ... EndSql — recomendado, suporta macros.
  2. TCQuery cSql NEW ALIAS <ALIAS> — antigo, sem macros (string crua).

Quando usar

  • Edit/criação de qualquer query SQL no fonte ADVPL.
  • Refator de SQL legado (TCQuery → BeginSql).
  • Revisão de regra PERF-001..006 ou SEC-001.
  • Antes de testar performance — sem macros, queries dão problema em produção multi-empresa.

As 5 macros obrigatórias

MacroO que fazOutputSafe injection
%table:TABLE%Resolve nome físico (SA1010 em vez de SA1)identifiersim
%xfilial:TABLE%Valor atual da filial, já entre aspasstring literalsim
%notDel%Filtro D_E_L_E_T_ <> '*' (registros não-deletados)predicatesim
%exp:VAR%Binda variável ADVPL com escaping automáticoscalar literalsim
%Order:TABLE%Resolve ORDER BY da chave primária da tabelacolumnssim

Concatenação com + para incluir variável é proibida — viola SEC-001 (crítico, SQL injection).

Exemplo correto — BeginSql

Local cCodCli := "000001"
Local cFilNF  := "01"

BeginSql Alias "QRY"
    SELECT SF2.F2_DOC, SF2.F2_SERIE, SF2.F2_EMISSAO, SD2.D2_COD, SD2.D2_QUANT
      FROM %table:SF2% SF2
      JOIN %table:SD2% SD2
        ON SD2.D2_FILIAL = SF2.F2_FILIAL
       AND SD2.D2_DOC    = SF2.F2_DOC
       AND SD2.D2_SERIE  = SF2.F2_SERIE
       AND SD2.D2_CLIENTE= SF2.F2_CLIENTE
       AND SD2.%notDel%
     WHERE SF2.F2_FILIAL = %xfilial:SF2%
       AND SF2.F2_CLIENTE= %exp:cCodCli%
       AND SF2.%notDel%
     ORDER BY %Order:SF2%
EndSql

// Tipagem de colunas — recomendado (PERF-003)
TCSetField("QRY", "F2_EMISSAO", "D")
TCSetField("QRY", "D2_QUANT",   "N", 11, 2)

While QRY->(!Eof())
    // ...processa
    QRY->(DbSkip())
EndDo
QRY->(DbCloseArea())

As 6 restrições de SQL embarcado (regras de lint)

RegraSeveridadeO que não fazer
PERF-001criticalSELECT * em BeginSql ou TCQuery — fetcha colunas inúteis, memo fields
PERF-002warningDbSeek dentro de While/For quando JOIN/IN resolveria
PERF-003warningFaltar TCSetField para datas/numéricos pós-query
PERF-004warningConcatenação de string com +/+= em loop (use array + Array2String)
PERF-005warningRecCount() para checar existência — use !Eof() (full scan)
PERF-006infoWHERE/ORDER BY em colunas sem índice (consulte SIX)
SEC-001criticalSQL com + cVar + em vez de %exp:cVar% — SQL injection

TCQuery (legacy) — quando aparece

// Estilo antigo — funciona, mas sem macros
Local cSql := "SELECT F2_DOC FROM " + RetSqlName("SF2") + " "
cSql += "WHERE F2_FILIAL = '" + xFilial("SF2") + "' "
cSql += "  AND F2_CLIENTE = '" + cCodCli + "' "
cSql += "  AND D_E_L_E_T_ <> '*'"

TCQuery cSql NEW ALIAS "QRY"

Migrate para BeginSql sempre que possível. Se manter TCQuery, NUNCA concatene variável de input — use %exp: em string template do BeginSql.

RetSqlName, xFilial (equivalentes ADVPL)

Quando precisar de SQL fora de BeginSql (ex: query dinâmica complexa):

  • RetSqlName("SA1") ↔ %table:SA1% (retorna nome físico).
  • xFilial("SA1") ↔ %xfilial:SA1% (retorna filial atual, sem aspas — precisa adicionar).
  • D_E_L_E_T_ <> '*' ↔ %notDel%.

Workflow recomendado

  1. Antes de escrever SQL, rode /plugadvpl:sql --op select --table SF2 para ver exemplos existentes no projeto.
  2. Use sempre BeginSql ... EndSql para queries novas.
  3. Liste explicitamente as colunas (SELECT F2_DOC, F2_SERIE, ...) — nunca SELECT *.
  4. Adicione %notDel% em toda tabela ADVPL que aparecer no FROM/JOIN.
  5. Adicione %xfilial:TABLE% no WHERE para filtro multi-filial.
  6. Bind variáveis com %exp: — nunca concatene.
  7. Após EndSql, chame TCSetField para D (data) e N (numérico).
  8. Sempre DbCloseArea() no fim ou em Recover.

Anti-padrões

// SEC-001 — SQL injection
cSql := "SELECT * FROM SA1010 WHERE A1_COD = '" + cCod + "'"

// PERF-001 — SELECT *
BeginSql Alias "QRY"
    SELECT * FROM %table:SA1% SA1 WHERE SA1.%notDel%
EndSql

// PERF-002 — DbSeek em loop
While SC5->(!Eof())
    DbSelectArea("SA1")
    DbSetOrder(1)
    DbSeek(xFilial("SA1") + SC5->C5_CLIENTE)  // N seeks; melhor um JOIN
    SC5->(DbSkip())
EndDo

// PERF-005 — RecCount para checar existência
If RecCount() > 0   // full scan; melhor !Eof()

Referência rápida

Macro / funçãoEquivalenteQuando
%table:T%RetSqlName("T")FROM/JOIN
%xfilial:T%"'" + xFilial("T") + "'"WHERE T_FILIAL =
%notDel%D_E_L_E_T_ <> '*'Todo predicate de tabela
%exp:cVar%"'" + cVar + "'" (NÃO)Bind seguro de variável
%Order:T%IndexKey() da chave 1ORDER BY
TCSetField—Pós-query, tipagem

Comandos plugadvpl relacionados

  • /plugadvpl:sql --op {select|insert|update|delete} --table <T> — busca SQL existente.
  • /plugadvpl:lint <arq> — executa PERF-001..006 e SEC-001.
  • /plugadvpl:tables <T> — lista quem usa a tabela.

Referência profunda

Para detalhes completos (~1.6k linhas), consulte reference.md ao lado deste arquivo:

  • Catálogo completo de macros %-prefixed (%table%, %notDel%, %xfilial%, %exp%, %Order%, %Limit%, %top%, %FieldsList%).
  • Diferenças entre BeginSql/TCQuery/TCGenQry e quando usar cada uma.
  • Padrões de paginação (LIMIT/OFFSET por DBMS — Oracle rownum × SQL Server TOP × Postgres LIMIT).
  • Uso correto de TCSetField para tipagem pós-query e implicações de performance.
  • Exemplos de queries complexas com JOIN multi-tabela + filtros de filial + tratamento de NULL.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.