Um banco de dados local, escrito em Object Pascal (Free Pascal), com tabelas, consultas e persistência em arquivo — sem depender de nenhuma engine externa (SQLite, MySQL, etc). O objetivo é entender e implementar, na prática, as peças que formam um banco de dados de verdade: definição de esquema, armazenamento de linhas, leitura/escrita em disco e um motor de consultas simples.
A maioria dos tutoriais de "como funciona um banco de dados" fica na teoria. Aqui a ideia foi implementar do zero, em uma linguagem estaticamente tipada e sem coletor de lixo automático (o que obriga a pensar em ciclo de vida de memória), as quatro camadas que qualquer banco de dados relacional tem:
- Tipos — o que uma coluna pode guardar.
- Tabela — a estrutura em memória e as operações sobre ela.
- Persistência — como a tabela vira bytes em disco e volta.
- Consultas — como filtrar e projetar dados sem escrever um parser SQL inteiro.
src/
MiniDBTypes.pas Tipos de campo (INTEIRO, TEXTO, BOOLEANO, DATA) e valores
MiniDBTable.pas Classe TTabela: colunas, linhas, inserir/apagar/atualizar
MiniDBStorage.pas Serialização binária de uma TTabela para arquivo .mdb
MiniDBQuery.pas Motor de consulta: SELECT (projeção) e WHERE (filtro)
MiniDB.pas Classe TMiniDB: várias tabelas + integração com o disco
main.pas Programa CLI (REPL) que interpreta os comandos
data/
*.mdb Arquivos binários gerados por tabela (não versionados)
bin/
minidb Executável compilado (não versionado)
Cada unit tem uma responsabilidade única e depende apenas das anteriores na
lista acima — MiniDBTypes não conhece MiniDBTable, MiniDBTable não
conhece MiniDBStorage, e assim por diante. Isso deixa claro onde mexer
quando se quer, por exemplo, trocar o formato do arquivo em disco sem tocar
no motor de consultas.
Cada tabela vira um arquivo binário próprio em data/<nome>.mdb, sem
depender de nenhuma lib de serialização:
[nome da tabela]
[quantidade de campos]
[nome do campo][tipo do campo] x N
[quantidade de linhas]
[valor do campo 1][valor do campo 2]... x N por linha
Strings são gravadas como [tamanho: Word][bytes]; os demais tipos usam o
tamanho nativo do Pascal (LongInt, Boolean, TDateTime). Não há
compressão nem índice em disco — cada leitura recarrega a tabela inteira
para a memória, o que é intencional: o foco é didático, não performance.
| Tipo | Equivalente Pascal | Exemplo de literal |
|---|---|---|
INTEIRO |
LongInt |
42 |
TEXTO |
ShortString |
Ana |
BOOLEANO |
Boolean |
VERDADEIRO/FALSO |
DATA |
TDateTime |
31/12/2016 |
Requer o Free Pascal Compiler (testado com a série 3.x).
fpc -Fusrc -FEbin -obin/minidb src/main.pasO executável é gerado em bin/minidb. A pasta data/ é criada
automaticamente na primeira execução, caso não exista.
./bin/minidbO programa abre um prompt (minidb>) que interpreta comandos de texto —
não é SQL, é uma sintaxe própria, mais simples, pensada para este projeto:
CRIAR TABELA usuarios (nome:TEXTO, idade:INTEIRO)
INSERIR EM usuarios VALORES (Ana, 30)
INSERIR EM usuarios VALORES (Bruno, 25)
SELECIONAR * DE usuarios
SELECIONAR * DE usuarios ONDE idade = 30
APAGAR DE usuarios ONDE idade = 25
LISTAR TABELAS
SALVAR usuarios
SALVAR TUDO
AJUDA
SAIR
Ao iniciar, o programa carrega automaticamente todas as tabelas já salvas em
data/. Nada é persistido em disco até um SALVAR <tabela> ou
SALVAR TUDO — até lá, as alterações existem só na memória do processo,
como em qualquer banco de dados com um passo explícito de commit.
minidb> CRIAR TABELA usuarios (nome:TEXTO, idade:INTEIRO)
Tabela "usuarios" criada com 2 campo(s).
minidb> INSERIR EM usuarios VALORES (Ana, 30)
1 linha inserida.
minidb> INSERIR EM usuarios VALORES (Bruno, 25)
1 linha inserida.
minidb> SELECIONAR * DE usuarios
nome idade
-------------------
Ana 30
Bruno 25
(2 linha(s))
minidb> SALVAR usuarios
Tabela "usuarios" salva.
minidb> SAIR
Na próxima execução, usuarios já aparece em LISTAR TABELAS com os dados
que foram salvos.
Este é um projeto de estudo, não um substituto para um banco de verdade. Coisas que ficaram de fora de propósito, para manter o escopo enxuto:
- Sem índices — toda busca percorre a tabela inteira (
O(n)). WHEREsó compara um único campo por vez, e o CLI só expõe igualdade (=); os operadores<>,>e<já existem no motor de consultas (MiniDBQuery.pas), mas ainda não têm sintaxe no REPL.- Sem transações, sem controle de concorrência — um processo por vez.
- Sem
JOINentre tabelas. TEXTOé limitado a 255 caracteres (ShortString).
Este projeto está sob a licença GPL-3.0. Veja o arquivo LICENSE.