Skip to main content

Module batch

Module batch 

Source
Expand description

DML em lote (batch) — o recurso “principal” de array DML do Firebird 4+.

Um Batch insere/atualiza/exclui muitas linhas com uma única instrução preparada, acumulando mensagens no cliente e enviando-as ao servidor em uma ida só. É muito mais rápido que executar a instrução linha a linha.

let mut batch = conn.create_batch(&tx, "INSERT INTO t (a, b) VALUES (?, ?)")?;
batch.add(&[Value::Int(1), Value::Text("um".into())])?;
batch.add(&[Value::Int(2), Value::Text("dois".into())])?;
let result = batch.execute(&mut conn, &tx)?;   // envia + executa
println!("{} linhas afetadas no total", result.total_affected());
batch.close(&mut conn)?;                        // libera no servidor

§Protocolo (FB4+, op codes 99–103)

Descoberto por captura de um cliente C usando a interface OO IBatch:

  1. op_batch_create (99): stmt | blr(cstring) | msglen(u32) | pb(cstring). O BLR descreve o formato da mensagem (igual ao in_blr de op_execute); msglen é o tamanho do buffer de mensagem do lado do cliente.
  2. op_batch_msg (100): stmt | count(u32) | mensagens, cada mensagem no mesmo formato compacto (bitmap de nulos + valores XDR) usado em op_execute.
  3. op_batch_exec (101): stmt | transaction. Responde com op_batch_cs.
  4. op_batch_cs (103): estado de conclusão (contagens por linha + erros).
  5. op_batch_rls (102): libera o batch no servidor.

O cliente C agrupa create+msg e usa op_batch_sync (110) para drenar as respostas adiadas; nós, sendo síncronos, lemos a resposta de cada op na hora.

§BLOBs em lote (política STREAM, op_batch_blob_stream 105)

Quando a instrução tem coluna BLOB, Connection::create_batch ativa a política BLOB_STREAM no PB (TAG_BLOB_POLICY = 3). O chamador então usa Batch::add_blob para registrar cada blob e recebe um id (quad) para pôr no campo da linha. Em Batch::execute, antes das mensagens, enviamos:

op_batch_blob_stream (105): stmt | length(u32) | stream. O stream é a concatenação CRUA (sem padding) dos blobs, cada um id(quad 8B BE) | size(4B BE) | bpb_size(4B BE) | bpb | dados. O length NÃO é o número de bytes no wire: é o tamanho do buffer que o servidor aloca — a soma de align4(16 + bpb + dados) de cada blob — e deve ser múltiplo de 4 (o servidor rejeita caso contrário). Ao percorrer o stream (ver xdr_blob_stream no servidor), ele avança o ponteiro do buffer com alinhamento de 4 SEM consumir bytes do wire para o padding; o laço termina quando o que resta é menor que um cabeçalho (16 B) ou chega a zero. Por isso o wire carrega menos bytes que length, e a próxima op pode começar em offset não múltiplo de 4. Confirmado por captura do 11.batch.cpp (conteúdo 30 B → length 32; 33 B → 36) e pelo código do servidor. Os blobs vão antes das mensagens porque a linha referencia o id já registrado.

op_batch_regblob (104): stmt | id_existente(quad 8B BE) | id_batch(quad). Mapeia um BLOB já gravado fora do batch (Connection::write_blob) a um id local, evitando reenviar os dados. Ver Batch::register_blob.

op_batch_set_bpb (106): stmt | bpb(cstring). Define o BPB padrão dos blobs do batch; o servidor lê o isc_bpb_type para marcar os blobs como segmentados ou stream. Ver Batch::set_default_bpb / Batch::set_segmented. Em modo segmentado, cada segmento no stream é um u32 big-endian com o comprimento seguido dos bytes, SEM padding; já o campo size do blob segue a contabilidade do buffer do servidor (cabeçalho de 2 bytes alinhado a 2), ou seja align2(2 + len). Capturado da Parte 3 do 11.batch.cpp.

Structs§

Batch
Um lote de mensagens vinculado a uma instrução preparada no servidor.
BatchError
Um erro detalhado de uma mensagem específica do lote.
BatchOptions
Opções de criação de um Batch (clumplets do op_batch_create).
BatchResult
Resultado da execução de um lote: o estado de conclusão por mensagem.