P.2. SQLite com Tcl/Tk

Nesta seção vamos organizar algumas informações sobre o uso do banco de dados SQLite com a linguagem Tcl/Tk.

As fontes de consulta para essa seção foram: The Definitive Guide to SQLite, 2010, Tcl 8.5 Networking Programming, 2010, The Tcl interface to the SQLite library e SQLite and Tcl.

O SQLite foi originalmente criado como uma extensão para o interpretador Tcl, por isso oferece suporte à Tcl desde o início, facilitando o seu uso a partir de um programa em Tcl.

Para começar instalamos a extensão da Tcl para acessar o SQLite:

apt-get install libsqlite3-tcl

Para carregar a extensão, dentro de um programa, basta usar o comando:

package require sqlite3

Para se conectar a um banco de dados use o comando sqlite3 que gera (ou retorna) um descritor de arquivo (ou identificador), ou seja, um nome para o canal que será usado para ler ou escrever dados no banco de dados.

Este comando tem dois argumentos: o primeiro é o nome do identificador de banco de dados (Ex: db) a ser criado e o segundo é o caminho para o arquivo de banco de dados (Ex: ./foods.db).

Criamos o programa foods.tcl com o seguinte código inicial:

#!/usr/bin/env tclsh
  
package require sqlite3

puts "\nConectando"

sqlite3 db ./foods.db

Se passarmos o nome de um arquivo novo para o comando sqlite3 será criado um novo banco de dados. E se passarmos o argumento :memory: para o comando sqlite3 será criado um banco de dados apenas na memória.

O identificador do banco de dados é o meio de conexão com o banco de dados especificado. No entanto a conexão ainda não está aberta. A conexão só será aberta quando você tentar usá-la.

A escolha do nome do identificador de banco de dados é livre, e ele é o único objeto através do qual é possível acessar o banco de dados. Também é possível abrir o mesmo banco de dados várias vezes com identificadores diferentes.

O identificador é um objeto que oferece vários métodos, sendo o mais importante o eval.

O método eval permite a execução de consultas SQL no banco de dados com a sintaxe:

Para desconectar, basta usar o comando close do identificador do banco de dados. Isso automaticamente reverterá quaisquer transações pendentes.

nome_do_identificador eval {consulta_SQL} [nome_array] {[script]}

Atenção

Por padrão o SQLite não reconhece a restrição FOREIGN KEY, e por isso esse reconhecimento deve ser ativado logo após a conexão com o banco de dados com o comando:

db eval {PRAGMA foreign_keys = ON;}

P.2.1. Executando uma Consulta

As consultas são executadas com o método eval, o qual processa uma ou mais consultas de cada vez.

Uma das formas de uso do método eval é iterar todas as linhas em um script seguindo o código SQL. O script será executado uma vez para cada linha retornada no conjunto de resultados. E os campos em cada linha são considerados variáveis locais dentro do script.

Por exemplo, vamos acrescentar a seguinte consulta no programa foods.tcl:

puts "\nSelecionando 5 registros"

db eval {SELECT * FROM foods LIMIT 5} {

    puts "$id $name"
}

É possível também atribuir os valores dos diferentes campos da tabela a um array:

puts "\nSelecionando 5 registros."

db eval {SELECT * FROM foods LIMIT 5} values {

puts "$values(id) $values(name)"

}

A saída de ambas as consultas é:

~/SQLite$ ./foods.tcl

Conectando

Selecionando 5 registros
1 Bagels
2 Bagels, raisin
3 Bavarian Cream Pie
4 Bear Claws
5 Black and White cookies

O retorno do comando:

db eval {SELECT * FROM foods LIMIT 5}

é uma lista cujos elementos são os campos da tabela foods. A lista pode ser visualizada com o comando:

puts [db eval {SELECT * FROM foods LIMIT 5}]

Retorno:

  1 1 Bagels 2 1 {Bagels, raisin} 3 1 {Bavarian Cream Pie} 4 1 {Bear Claws} 5 1 {Black and White cookies}

Essa lista corresponde a 5 registros, cada um dos quais possui 3 campos (id, type_id e name).

P.2.2. Inserindo, Modificando e Removendo Dados

O exemplo seguinte mostra como realizar as operações de: inserção, modificação e remoção de dados e usamos o método changes para exibir o número de registros que sofreram modificações:

db eval begin

puts "\nAtualizando o id de todos os registros."

db eval { UPDATE foods SET type_id=0 }

puts "Modificações : [db changes]"

puts "\nRemovendo todas as linhas."

#Remover todas as linhas
db eval { DELETE FROM foods }

puts "Modificações : [db changes]"

puts "\nInserindo uma linha."

#Inserindo uma linha
db eval { INSERT INTO foods (type_id, name) VALUES (9, 'Junior Mints') }

puts "Modificações : [db changes]"

puts "last_insert_rowid() : [db last_insert_rowid]"

puts "\nCancelando as operações."

db eval ROLLBACK

Saída:

Atualizando o id de todos os registros.
Modificações : 417

Removendo todas as linhas.
Modificações : 417

Inserindo uma linha.
Mudanças : 1
last_insert_rowid() : 1

Cancelando as operações.

Para fechar o banco de dados basta executar o comando CLOSE:

db CLOSE

P.2.3. Consultando a Estrutura do Banco de Dados

Todo banco de dados SQLite possui uma tabela com o nome SQLITE_MASTER que define o esquema (schema) para o banco de dados com a seguinte estrutura: (Fonte: www.sqlite.org/faq.html#q7)

  CREATE TABLE sqlite_master (
  type TEXT,
  name TEXT,
  tbl_name TEXT,
  rootpage INTEGER,
  sql TEXT
);

O campo name será o nome da tabela. Então, para obter uma lista de todas as tabelas no banco de dados, use o seguinte comando: (Fonte: https://www.tcl.tk/community/tcl2004/Presentations/D.RichardHipp/slides/slides-all.html)

puts [db eval {SELECT name FROM sqlite_master WHERE type='table'}]
episodes foods foods_episodes food_types foods_copy

E para ver a estrutura de uma tabela, por exemplo foods:

puts [db onecolumn {SELECT sql FROM sqlite_master WHERE name='foods'}]
CREATE TABLE foods(
  id integer primary key,
  type_id integer,
  name text )

P.2.4. Links

ActiveTcl User Guide

Tcl/Tk and SQLite - D. Richard Hipp - 11th Annual Tcl/Tk Conference - New Orleans - 2004

SQLite3 and incrblob

Arquivos de teste da biblioteca SQLite

Using SQLite From Tcl

SQLite and Tcl