Instituto de Computação
Universidade Estadual de Campinas
MC202 – Estruturas de Dados (A, B, C, D)
BDMoSS
30 de setembro de 2011
1
Problema
Desta vez um Banco de Dados, em Memória, Super Simples (BDMoSS) precisa ser criado
para gerenciar pequenas coleções de registros. Esse Banco de Dados (BD) suporta, de forma
restrita, apenas 6 cláusulas: CREATE, DELETE, DUMP, INSERT, SELECT e UPDATE. O formato de
cada uma destas cláusulas pode ser visto nas Figuras 1–5.
,
CREATE
TABLE
(
nome
nome
)
tipo
;
;
DUMP
Figura 1: Cláusulas CREATE e DUMP
DELETE
FROM
nome
WHERE
nome
IN
..
start
;
end
Figura 2: Cláusula DELETE
,
INSERT
INTO
(
nome
,
)
nome
(
valor
)
;
Figura 3: Cláusula INSERT
,
SELECT
(
)
nome
WHERE
FROM
nome
nome
IN
..
start
;
end
Figura 4: Cláusula SELECT
,
UPDATE
nome
(
nome
WHERE
,
)
(
nome
)
valor
IN
start
Figura 5: Cláusula UPDATE
1
..
end
;
Um retângulo qualquer nas Figuras 1–5 com o texto “tipo” indica que o conteúdo do mesmo
será substituído por INTP (chave primária de tipo inteiro), INT, ou TEXT (uma string qualquer).
Caso o texto seja “nome” então o mesmo pode representar ou um nome de uma tabela ou o nome
de uma das colunas da tabela. No lugar do texto “valor” estará presente ou um número inteiro
ou uma string. Por último, “start” e “end” são números inteiros (start ≤ end) e representam
uma faixa de valores.
A leitura das cláusulas já está pronta, você precisa apenas implementar o BD. Na sua
implementação, as subcláusulas WHERE trabalharão somente com colunas que representam chaves primárias. Além disso, cada uma das tabelas do seu BD será descrito por uma Árvore
B+ onde as chaves dos nós serão dadas pelos valores das chaves primárias – a entrada criará
apenas tabelas contendo uma única coluna como chave primária. No seu BD, registros podem
ter valores vazios (representados por “NULL”) em qualquer uma das colunas com exceção do
campo da chave primária. A inserção de um registro em uma tabela com uma chave primária
já existente nesta tabela não tem efeito algum, assim como um UPDATE ou SELECT ou DELETE
com valores de chaves primárias que não existem na respectiva tabela. E, também, a entrada
nunca fornecerá cláusulas que: 1) criam duas tabelas com o mesmo nome; 2) utilizam tabelas
ou colunas inexistentes; 3) fazem uso de uma mesma coluna repetidas vezes.
Neste trabalho não é necessário que a cláusula DELETE realmente remova chaves, você
pode apenas marcar um item como removido (e tomar os devidos cuidados). Você também
não precisa se preocupar com a atualização de chaves primárias, pois esta operação não é
permitida no BDMoSS. A criação de uma tabela com n colunas implica em criar uma Árvore
B+ de ordem n + 2 + k, onde k = (1 + último digito do seu RA) mod 3. Logo, cada nó deverá
ter no máximo n + 2 + k registros.
Uma Árvore B+ é bastante semelhante à Árvore B comum. As duas principais diferenças
são: 1) todo conteúdo das chaves ficam nas folhas; os nós internos são utilizados apenas
para chegar até as mesmas; 2) todas as folhas ficam ligadas, tornando eficiente uma busca
sequencial em amplitude. Como todas as chaves (e seus respectivos conteúdos) ficam nas
folhas, uma inserção que requer divisão de nós não é exatamente igual àquela em uma Árvore
B. A diferença é que quando um nó folha é dividido, sua chave mediana é mantida na folha
e copiada para o nó pai. Se o nó pai precisar ser dividido, a chave mediana do pai é movida
para o pai do nó pai. A Figura 6 ilustra uma estratégia para esta situação.
17 35 50
3 5 17
20 35
17 35 50
48 50
83 90 91
3 5 17
20 35
48 50
83 90
91
(b) Nó folha é dividido; copia chave 90 no pai
(a) Árvore inicial
35
17 35
3 5 17
20 35
17
50 90
48 50
51 83 90
3 5 17
91
(c) Nó interno é dividido; propaga chave 35
50 90
20 35
48 50
51 83 90
(d) Nova raiz é criada
Figura 6: Exemplo de inserção da chave 51 numa Árvore B+ de ordem 3
2
91
2
Entrada
A entrada consiste em uma sequência de cláusulas bem formadas para o BDMoSS.
Exemplo:
CREATE
INSERT
INSERT
DUMP;
UPDATE
DELETE
SELECT
3
TABLE aluno (ra INTP, nome TEXT, semestre INT);
INTO aluno (ra, nome, semestre) (123, "Bob Esponja", 2);
INTO aluno (ra, semestre, nome) (321, 3, "Sandy");
aluno (semestre) (1) WHERE ra IN 123..123;
FROM aluno WHERE ra in 150..400;
(nome, semestre) FROM aluno;
Saída
Seu programa deve exibir os resultados das execuções das cláusulas DUMP e SELECT no momento
em que elas são especificadas. A saída de um DUMP deve exibir: 1) a quantidade de tabelas no
BD, quantidade total de linhas em todas tabelas e número de registros removidos, atualizados
e selecionados; 2) todas as tabelas do BD na ordem em que foram criadas. A saída de um
SELECT deve incluir o cabeçalho da tabela, conforme a ordem imposta pela cláusula, e os
resultados obtidos. Após cada tabela exibida, imprima uma linha em branco. O formato da
saída a seguir deve ser utilizado. Para decidir pela largura de uma coluna, utilize a fórmula:
max(|nome da coluna|, max(|item já inserido na coluna|), |00 N U LL00 |) + 2.
Exemplo:
1 tabela
2 linhas
0 deletes, 0 updates, 0 selects
aluno
+------+-------------+----------+
| ra
| nome
| semestre |
+======+=============+==========+
| 123 | Bob Esponja | 2
|
+------+-------------+----------+
| 321 | Sandy
| 3
|
+------+-------------+----------+
+-------------+----------+
| nome
| semestre |
+=============+==========+
| Bob Esponja | 1
|
+-------------+----------+
3
4
Avaliação
A nota deste laboratório será dada por:


SuSy



}|
z



{


n


X






(teste
==
correto)
?
1
:
0
i




 


i=1
 + 3 DQ
nota = CS 7 



n



















A variável DQ corresponde a documentação adequada (comentários no código fonte) e
qualidade do código entregue. A variável booleana CS indica se o código em C está coerente
com o enunciado da Seção 1.
Seu trabalho deve ser dividido da maneira seguinte:
btree.h : Protótipos para Árvore B+ ;
btree.c : Implementação da Árvore B+ ;
db.h : Protótipos para o BD (parcialmente fornecido);
db.c : Implementação do BD;
input.h : Contém os protótipos necessários para manuseio da entrada (fornecido);
input.c : Trata toda a entrada (fornecido);
main.c : Chama funções em input.c e encaminha consultas para o BD (fornecido);
5
Entrega
• Submissão de código ao SuSy (15 tentativas no máximo): de 30 de setembro às 12:00 a
14 de outubro às 02:00
6
Links extras
I http://www.db-class.org/course/video/preview_list
I The Ubiquitous B-tree
I Organization and Maintenance of Large Ordered Indices
4
Apêndice A – Construção de uma Árvore B+
A Figura 7 expande a Figura 6 de modo a apresentar a construção por etapas da árvore
resultante pela estratégia escolhida.
50
50
17 50
17 50 90
(a) Inserção das
chaves 17, 50 e
90 na árvore vazia
83 90
3
17 50
(b) Inserção da chave 83; nó folha (c) Inserção das chaves 3 e 91
é dividido e chave 50 é copiada
17 50
17 50
3
5
17
83 90 91
50
3
83 90 91
(d) Inserção da chave 5; nó folha é dividido e chave
17 é copiada
5
17
20 35 50
83 90 91
(e) Inserção das chaves 20 e 35
17 35 50
3
5
17
20 35
48 50
83 90 91
(f) Inserção da chave 48; nó folha é dividido e chave 35 é copiada
35
17
3
5
17
20 35
50 90
48 50
51 83 90
91
(g) Inserção da chave 51; veja Figura 6
Figura 7: Construção passo a passo de uma Árvore B+ de ordem 3 até chegar na árvore
resultante da Figura 6
5
Apêndice B – Entendendo as cláusulas
É importante entender as cláusulas das Figuras 1–5 para saber como seu BD deve operar. Se
você já conhece SQL (Structured Query Language), este Apêndice pode ser ignorado.
Uma cláusula CREATE determina que uma tabela de nome x deve ser criada com um mais
campos de nome ci e tipo ti . Durante a criação da tabela, a ordem das colunas é fixada
e a mesma deve ser respeitada na execução de um DUMP. Esta tabela, inicialmente vazia,
eventualmente será objeto de manipulação. As cláusulas SELECT, INSERT, UPDATE e DELETE
são aquelas que manipulam as tabelas existentes.
Um SELECT é divido em três partes: 1) definição das colunas dos registros a serem retornadas; 2) nome da tabela sobre a qual será feito a busca; 3) restrições a cerca de quais registros
devem ser retornados (opcional). Neste trabalho, o terceiro item é restrito a uma forma limitada para o WHERE. A subcláusula WHERE é a responsável por delimitar quais registros devem
ser retornados, sempre baseado unicamente nos valores das chaves (denominadas de chaves
primárias). O UPDATE é responsável por atualizar valores de certos registros em uma dada
tabela. Esta cláusula é divida da mesma forma que o SELECT, porém os registros definidos
serão atualizados ao invés de listados.
Para realizar um INSERT precisamos saber (nesta ordem): 1) o nome da tabela que será
manipulada; 2) nomes dos campos que terão algum valor; 3) valores para os campos especificados. Dessa forma, para inserir uma nova entrada na Árvore B+ , criamos um novo registro
no mesmo formato daquele definido durante a criação da tabela mas possivelmente deixamos
de preencher alguns campos e/ou utilizamos outra ordem. A inserção finaliza com a criação
de uma nova folha na Árvore B+ da tabela sob operação.
O DELETE, como o nome diz, remove registros criados por INSERTs. Para este trabalho, é
obrigatório o uso do WHERE para delimitar os registros a serem removidos.
Minha primeira tabela
Para por em prática os conceitos, vamos considerar a criação de uma tabela que tem registros
a cerca de países. Essa tabela é criada com a cláusula
CREATE TABLE country (id INTP, short TEXT, name TEXT);
definindo que a tabela tem 3 colunas: id que é um inteiro e é a chave da tabela, short e name
que são do tipo TEXT. Agora, vamos inserir 3 registros nesta tabela:
INSERT INTO country (short, name, id) ("BR", "Brazil", 76);
INSERT INTO country (name, short, id) ("Bahamas", "BH", 44);
INSERT INTO country (id, short, name) (1000, "YT", "Mayotte");
Neste momento, a Árvore B+ desta tabela tem 3 folhas com chaves 44, 76 e 1000. Cada
uma destas folhas leva ao conteúdo do registro que foi criado durante cada INSERT. Para buscar
esses registros, utilizamos a cláusula SELECT. Se desejamos encontrar os nomes dos países com
id entre 30 e 50 é feito um
SELECT (name) FROM country WHERE id IN 30..50;
6
que resulta em
+---------+
| name
|
+=========+
| Bahamas |
+---------+
Para atualizar o nome de algum país, utilizamos a cláusula UPDATE. Por exemplo, se queremos mudar o nome de “Brazil” para “Brasil”, fazemos o seguinte:
UPDATE country (name) ("Brasil") WHERE id IN 76..76;
para verificar a alteração podemos utilizar a cláusula DUMP que produz
1 tabela
3 linhas
0 deletes, 1 update, 1 select
country
+------+-------+---------+
| id
| short | name
|
+======+=======+=========+
| 44
| BH
| Bahamas |
+------+-------+---------+
| 76
| BR
| Brasil |
+------+-------+---------+
| 1000 | YT
| Mayotte |
+------+-------+---------+
A última operação que é possível fazer é a remoção de registros. No caso, se desejarmos
remover todas as entradas precisamos saber o valor mínimo e máximo das chaves na tabela.
Neste exemplo podemos fazer a operação seguinte:
DELETE FROM country WHERE id IN -1..1500;
seguido de um DUMP para visualização:
1 tabela
0 linhas
3 deletes, 1 update, 1 select
country
+------+-------+---------+
| id
| short | name
|
+======+=======+=========+
Repare que muitas chaves não existem entre −1 e 1500, portanto elas são ignoradas.
7
Download

BDMoSS - students.ic.unicamp.br