Skip to content

fix: OnQueryError entregava os argumentos ao contrário - #56

Merged
NullSablex merged 1 commit into
masterfrom
fix/query-file-reporta-erro
Sep 26, 2026
Merged

NullSablex merged 1 commit into
masterfrom
fix/query-file-reporta-erro

Conversation

@NullSablex

Copy link
Copy Markdown
Owner

Encontrado enquanto eu testava o mysql_query_file num servidor SA-MP de verdade. É um bug de comportamento, não de documentação.

O bug

O forward é declarado assim:

forward OnQueryError(errorid, const error[], const callback[], const query[], connId);

Mas o gamemode recebia os cinco valores na ordem inversa. Com uma tabela inexistente, medido no servidor:

parâmetro deveria receber recebia
errorid 1146 1 — o connId
error[] Table '…' doesn't exist SELECT * FROM tabela_inexistente
callback[] NuncaChamado ✅ correto
query[] SELECT * FROM tabela_inexistente MySqlError { ERROR 1146 … }
connId 1 1146 — o errorid

Causa: o exec_public! empilha os argumentos ao contrário, que é a convenção da pilha do AMX — então a ordem listada na chamada é a ordem em que o public recebe. O código listava começando pelo conn_id, como se precisasse inverter na mão. Agora lista na ordem do forward, com um comentário registrando o porquê.

Depois da correção, mesmo teste:

errorid  = 1146
error[]  = Table 'cbtest.tabela_inexistente' doesn't exist
callback = NuncaChamado
query[]  = SELECT * FROM tabela_inexistente
connId   = 1

Atenção para quem já usa: quem tratava OnQueryError vinha lendo a query no lugar da mensagem e o id da conexão no lugar do código de erro. Gamemodes que se acostumaram com a ordem errada precisam ser conferidos.

Junto, duas coisas da mesma área

1. A mensagem vinha com as tripas do Rust. O Display de mysql::Error embrulha a mensagem do servidor no nome da variante, então o script recebia MySqlError { ERROR 1146 (42S02): Table 'db.t' doesn't exist } — estrutura interna de Rust dentro de uma string Pawn. Para erro vindo do servidor passa a ser só a mensagem. O resto (IO, TLS, protocolo) mantém o texto completo, que é todo o detalhe que existe.

2. mysql_query_file falhava sem avisar quem disparou. Arquivo ilegível ou sem statements virava uma linha de log e false no retorno — que a forma sem callback, recomendada pela própria doc para schema, nunca vê. Eu mesmo caí nisso: apontei para scriptfiles/schema.sql, o caminho é relativo à raiz do servidor, e o gamemode seguiu achando que o schema tinha rodado.

Agora também dispara OnQueryError, com o caminho no lugar da query para a mensagem nomear o arquivo:

errorid=0 | query='scriptfiles/nao_existe.sql'
error='mysql_query_file: could not read 'scriptfiles/nao_existe.sql': No such file or directory (os error 2)'

O errorid é 0 porque a doc já promete isso para falha que não chegou ao servidor — inventar um número específico do plugin quebraria o contrato. O mysql_errno(connId) continua reportando MYSQL_ERROR_QUERY_FAILED. A linha do errorid em docs/errors.md foi ampliada para citar o caso do arquivo.

Verificação

Tudo medido num SA-MP 0.3.7 com MariaDB 11.8, não só compilado:

  • os cinco parâmetros conferidos um a um, antes e depois
  • mysql_query_file com caminho inválido, sem callback, chegando ao OnQueryError
  • cargo test — 177 passed, 1 ignored
  • cargo clippy --all-targets -- -D warnings — limpo
  • cargo fmt --check — limpo

O forward e declarado como

    OnQueryError(errorid, const error[], const callback[], const query[], connId)

mas o gamemode recebia os cinco valores na ordem inversa. Rodando contra
um servidor de verdade, uma tabela inexistente chegava assim:

    errorid  = 1          (era o connId)
    error[]  = SELECT * FROM tabela_inexistente        (era a query)
    query[]  = MySqlError { ERROR 1146 ... }           (era a mensagem)
    connId   = 1146       (era o errorid)

A causa esta no `exec_public!`: o macro empilha os argumentos ao
contrario, que e a convencao da pilha do AMX, entao a ordem listada na
chamada e a ordem em que o public recebe. O codigo listava comecando pelo
`conn_id`, como se precisasse inverter na mao. Agora lista na ordem do
forward, e um comentario registra o porque para nao regredir.

Quem tratava `OnQueryError` estava lendo a query no lugar da mensagem e o
id da conexao no lugar do codigo de erro. Vale conferir gamemodes que
tenham se acostumado com a ordem errada.

Junto, duas coisas da mesma area:

1. A mensagem vinha com as tripas do Rust. `mysql::Error` embrulha a
   mensagem do servidor no nome da variante, entao o script recebia
   `MySqlError { ERROR 1146 (42S02): Table 'db.t' doesn't exist }`. Para
   erro vindo do servidor passa a ser so a mensagem; o resto (IO, TLS,
   protocolo) mantem o texto completo, que e todo o detalhe que existe.

2. `mysql_query_file` falhava sem avisar quem disparou. Arquivo ilegivel
   ou sem statements virava linha de log e `false` no retorno - que a
   forma sem callback, que a propria doc recomenda para schema, nunca ve.
   Agora tambem dispara `OnQueryError`, com o caminho no lugar da query
   para a mensagem nomear o arquivo. O `errorid` e 0, como a doc ja
   promete para falha que nao chegou ao servidor.
@NullSablex
NullSablex merged commit 8e38acd into master Sep 26, 2026
11 checks passed
@NullSablex
NullSablex deleted the fix/query-file-reporta-erro branch September 26, 2026 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant