Tcl/Tk
Curso On-Line de Programação

Acessando um banco de dados ODBC

A interface ODBC-Tcl oferece diversos comandos que permitem o acesso aos bancos de dados ODBC.

Para acrescentar o suporte aos bancos de dados ODBC em seus programas, você deve incluir o comando a seguir, logo no início de seu programa:

package require tclodbc
Eu recomendo que sempre que for possível, você utilize o ODBC para acessar bancos de dados no Windows e também no Linux, pois fazendo assim, você tornará seus programas mais portáveis, devido ao uso de uma API única. De fato, eu acredito que, com o advento do UnixODBC e do TclODBC para o MacOS, o ODBC deverá se tornar a interface oficial do Tcl para acesso a bancos de dados. Na verdade, a versão UNIX do TclODBC, está sendo mantida pela Ajuba Solutions, o mantenedor oficial do Tcl. Assim podemos esperar que nas próximas versões do Tcl, o TclODBC faça parte integrante da distribuição oficial do produto.
 

Instalando o TclODBC no Windows

Para instalar o TclODBC siga os seguintes passos:
 

  1. Faça o download do arquivo tclodbc22.zip do meu site: http://www.souzamonteiro.com/download_freeware.shtml;
  2. Descompacte o arquivo em um diretório temporário;
  3. Mude para o diretório onde você descompactou os arquivos;
  4. Dê um duplo clique no arquivo setup.tcl;
  5. Confirme a instalação.
Isso instalará o tclodbc no diretório C:\Arquivos de Programas\Tcl\lib\tclodbc.
 

Instalando o TclODBC no Linux

Para instalar o TclODBC siga os seguintes passos( lembre-se que você deve ser o usuário root para instalar as bibliotecas ):

unixODBC:

  1. Certifique-se de ter instalado, em seu computador, as bibliotecas Qt 2.0 Free Edition ou superior, pois elas são necessárias para compilar os programas ODBCConfig e DataManager. Estas bibliotecas são usadas pelo KDE;
  2. Faça o download do unixODBC do meu site: http://www.souzamonteiro.com/download_freeware.shtml ou do site: http://www.unixodbc.org;
  3. Descompacte o arquivo digitando: tar xvzf unixODBC-1.8.12.tar.gz;
  4. Digite configure;
  5. Digite make;
  6. Digite make install;
Após a instalação você deverá instalar os drivers para os bancos de dados que você usará. Digite ODBCConfig na linha de comando do shell.

A janela a baixo será exibida:


Clique na guia Drivers e selecione a biblioteca do driver e a biblioteca do setup do driver. O nome da biblioteca do setup termina com S.so. Existe uma biblioteca de setup para cada driver.

Cada usuário pode configurar suas próprias entradas no User DSN, mas só o usuário root pode instalar drivers novos.

Você pode testar o seu banco de dados e executar comandos SQL através do programa DataManager. Veja a tela do programa na figura abaixo:
 


TclODBC:

  1. Instale os fontes do Tcl/Tk em seu computador. Se você não tiver, pege do meu site: http://www.souzamonteiro.com/download_freeware.shtml;
  2. Faça o download do arquivo tclodbc.tgz do meu site: http://www.souzamonteiro.com/download_freeware.shtml;
  3. Descompacte o arquivo digitando: tar xvzf tclodbc.tgz;
  4. Mude para o diretório tclodbc/;
  5. Digite autoconf para criar um script configure;
  6. Leia o arquivo README e verifique se há necessidade de passar alguns parâmetros para o script configure. Provavelmente --prefix=/usr/lib --exec-prefix=/usr/lib --with-tcl=/usr/src/rpm/BUILD/tcltk-8.0.4/tcl8.0.4;
  7. Execute o script configure;
  8. Eu recomendo que você edite o arquivo Makefile gerado e remova o parâmetro USE_TCL_STUBS=1 que é passado para o compilador;
  9. Digite: make;
  10. Digite: make install.
Isso instalará o pacote tclodbc em seu computador.
 

Criando um banco de dados

Para criar um banco de dados do Access( MDB ), copie e cole o fragmento de código abaixo:

# Carrega o TclODBC
package require tclodbc
# Cria o DSN
database configure config_dsn "Microsoft Access Driver (*.mdb)" [list "CREATE_DB=\"pizza.mdb\" General"]
database configure add_dsn "Microsoft Access Driver (*.mdb)" [list "DSN=pizza" "DBQ=pizza.mdb"]
# Conecta o banco de dados e cria as tabelas
database db pizza
db "CREATE TABLE districts (code VARCHAR (10), name VARCHAR (50));"
db "CREATE TABLE products (code VARCHAR (10), name VARCHAR (50));"
db "CREATE TABLE prices (district VARCHAR (10), product VARCHAR (10), price VARCHAR (10));"
# Disconecta o banco de dados
db disconnect
É claro que você deve verificar os erros retornados, mas nós ainda não falamos do tratamento de erros em Tcl. Isso será visto na aula 28.
 

A interface ODBC-Tcl

Os comandos oferecidos pela interface ODBC-Tcl são os seguintes:
 

Comando Descrição
database identificadorfonte usuário senha Cria um objeto database, identificado por identificador e o conecta à fonte( datasource ). O comando retorna o identificador.
database identificador string_de_conecção Cria um objeto database, identificado por identificador e o conecta à fonte( datasource ). O comando retorna o identificador.
database configure operação driver atributos Configura a fonte de dados ODBC( datasource ). Você pode adicionar uma fonte ao sistema, configurá-la ou remove-la. As operações são: add_dsn, config_dsn, remove_dsn, add_sys_dsn, config_sys_dsn, remove_sys_dsn.
database datasources Retorna uma lista com as fontes de dados( datasources ) configuradas, na forma: {nome_da_fonte nome_do_driver}.
database drivers Retorna uma lista dos drivers configurados, na forma: {nome_do_driver {atributo1=valor1 atributo2=valor2...}}.

Os comandos oferecidos pelos objetos database são:
 

Método Descrição
identificador consulta_SQL Executa uma consulta SQL e retorna o resultado em uma lista, onde cada ítem da lista corresponde a uma linha retornada.
identificador disconnect Disconecta o banco de dados.
identificador set opção valor Configura várias opções relativas à conecção. Veja a tabela de opções a seguir.
identificador get opção Retorna o valor de uma opção relativa à conecção. Vela a tabela de opções a seguir.
identificador commit Finaliza um transação, salvando os valores.
identificador rollback Cancela uma transação.
identificador tables ?string? Retorna os nomes de todas as tabelas no banco de dados que combinam com a string dada. Os caracteres % e _ são coringas.
identificador columns ?tabela? Retorna os nomes de todas as colunas na tabela dada, ou no banco de dados caso o nome da tabela seja omitido.
identificador indexes tabela Retorna uma lista de todos os índices da tabela especificada.
identificador typeinfo tipo Retorna infomações sobre o tipo de dado especificado.
identificador statement id condulta_SQL Cria um objeto statement. Veja os métodos suportados pelos objetos statement a seguir.
identificador eval proc consulta_SQL Executa uma procedure proc, para cada linha retornada na consulta SQL. O método passa para a procedure os valores das colunas retornadas. A procedure deve ter o seguinte cabeçalho: proc procedimento {coluna1 coluna2... colunaN} {corpo_do_procedimento...}.
identificador read vetor consulta_SQL Coloca o resultado da consulta no vetor associativo vetor. O vetor vetor tem a seguinte forma: vetor(valor_da_primeira_coluna_retornada, nome_da_coluna).
identificador read {vetor1 vetor2...} consulta_SQL Coloca o resultado da consulta no vetor associativo vetor. O vetor vetor1 tem a seguinte forma: vetor1(valor_da_primeira_coluna_retornada) e contém os valores de todas as linhas, somente da primeira coluna retornada. O vetor vetor2 tem a seguinte forma: vetor2(valor_da_segunda_coluna_retornada) e contém os valores de todas as linhas, somente da segunda coluna retornada e assim por diante.

As opções suportadas pelos métodos set e get são:
 

Opção Valor
autocommit booleano (0/1, on/off).
concurrency readonly, lock, values, rowver
maxrows Valor numérico.
timeout Valor numérico.
maxlength Valor numérico.
rowsetsize Valor numérico.
cursortype static, dynamic, forwardonly, keysetdriven
encoding Uma codificação válida.
noscan booleano (0/1, on/off).

Os métodos suportados pelos objetos statement são:
 

Método Descrição
id Executa a declaração e retorna os resultados imediatamente.
id execute consulta_SQL Executa a declaração, mas não retorna os valores. As linhas devem ser lidas uma a uma através do método fetch.
id fetch ?vetor? ?colunas? Retorna a próxima linha no resultado da consulta. Se for executado sem parâmetros retorna a linha em uma lista: {coluna1 coluna2...}. Vetor é um vetor associativo onde os nomes de cada elemento correspondem aos nomes das colunas retornadas: vetor(nome_da_coluna).
id rowcount Retorna o número de linhas afetadas pelo último comando INSERT, UPDATE ou DELETE. Alguns drivers também podem retornar o número de linhas retornadas por uma declaração SELECT.
id columns ?atributo1atributo2...? Retorna os atributos das colunas. Veja os atributos suportados, na tabela abaixo.
id set opção valor Configura várias opções relativas ao objeto statement. Vela a tabela de opções a seguir.
id get opção Retorna o valor de uma opção relativa ao objeto statement. Vela a tabela de opções a seguir.
id drop Remove o objeto statement da memória.
id eval proc consulta_SQL Veja os métodos dos objetos database acima.
id read vetor consulta_SQL Veja os métodos dos objetos database acima.
id read {vetor1 vetor2...} consulta_SQL Veja os métodos dos objetos database acima.

Os atributos suportados pelo método columns são:
 

Atributo Descrição
label Rótulo da coluna.
name Nome original da coluna.
displaysize A largura máxima da string de dados da coluna.
type Tipo em SQL padrão.
typename Tipo na string específica do banco de dados.
precision Precisão numérica.
scale Escala.
nullable Se a coluna puder conter NULL, será 1.
updatable Se a coluna puder ser atualizada, será 1.
tablename Nome da tabela fonte da coluna.
qualifiername Nome qualificador da tabela.
owner Dono da tabela.

As opções suportadas pelos métodos set e get são:
 

Opção Valor
concurrency readonly, lock, values, rowver
maxrows Valor numérico.
timeout Valor numérico.
maxlength Valor numérico.
rowsetsize Valor numérico.
cursortype static, dynamic, forwardonly, keysetdriven
noscan booleano (0/1, on/off).

Os tipos de dados SQL são: CHAR, NUMERIC, DECIMAL, INTEGER, SMALLINT, FLOAT, REAL, DOUBLE, VARCHAR.

Os tipos extendidos são: DATE, TIME, TIMESTAMP, LONGVARCHAR, BINARY, VARBINARY, LONGVARBINARY, BIGINT, TINYINT, BIT.
 

Exemplos

Considere as seguintes tabelas:
 

districts
code
name
1
Arenoso
2
Arvoredo
3
Av. Bete
4
Amaralina
5
Aeroporto
6
Barros Reis
7
Barbalho
8
Bonocô
9
Brotas
10
Boca do Rio

 
products
code
name
1
Pizza Média
2
Pizza Grande
3
Pizza Família
4
Lazanha
5
Filé

 
prices
district
product
price
1
1
12.00
1
2
13.90
1
3
17.00
1
4
13.90
1
5
13.90
2
1
12.00
2
2
13.90
2
3
17.00
2
4
13.90
2
5
13.90

Criando as tabelas

Abra o interpretador Tcl e copie e cole os comandos a seguir( troque o valor da variável user pelo seu nome de usuário ):

# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados e cria as tabelas
set user rlsm
database connect db pizza $user
db "CREATE TABLE districts (code VARCHAR (10), name VARCHAR (50));"
db "CREATE TABLE products (code VARCHAR (10), name VARCHAR (50));"
db "CREATE TABLE prices (district VARCHAR (10), product VARCHAR (10), price VARCHAR (10));"
# Disconecta o banco de dados
db disconnect
Inserindo dados nas tabelas
# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados e insere os dados
set user rlsm
database connect db pizza $user
db "INSERT INTO districts (code, name) VALUES (\'1\',\'Arenoso\');"
db "INSERT INTO districts (code, name) VALUES (\'2\',\'Arvoredo\');"
db "INSERT INTO products (code, name) VALUES (\'1\',\'Pizza Média\');"
db "INSERT INTO products (code, name) VALUES (\'2\',\'Pizza Grande\');"
db "INSERT INTO products (code, name) VALUES (\'3\',\'Pizza Família\');"
db "INSERT INTO products (code, name) VALUES (\'4\',\'Lazanha\');"
db "INSERT INTO products (code, name) VALUES (\'5\',\'Filé\');"
db "INSERT INTO prices (district, product, price) VALUES (\'1\',\'1\',\'12.00\');"
db "INSERT INTO prices (district, product, price) VALUES (\'1\',\'2\',\'13.90\');"
db "INSERT INTO prices (district, product, price) VALUES (\'1\',\'3\',\'17.00\');"
db "INSERT INTO prices (district, product, price) VALUES (\'1\',\'4\',\'13.90\');"
db "INSERT INTO prices (district, product, price) VALUES (\'1\',\'5\',\'13.90\');"
db "INSERT INTO prices (district, product, price) VALUES (\'2\',\'1\',\'12.00\');"
db "INSERT INTO prices (district, product, price) VALUES (\'2\',\'2\',\'13.90\');"
db "INSERT INTO prices (district, product, price) VALUES (\'2\',\'3\',\'17.00\');"
db "INSERT INTO prices (district, product, price) VALUES (\'2\',\'4\',\'13.90\');"
db "INSERT INTO prices (district, product, price) VALUES (\'2\',\'5\',\'13.90\');"
# Disconecta o banco de dados
db disconnect
Visualizando os valores contidos nas tabelas

Abra o interpretador Tcl e copie e cole os comandos a seguir( troque o valor da variável user pelo seu nome de usuário ):

Implementação 1:

# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados
set user rlsm
database connect db pizza $user
# Executa a consulta
set res [db "SELECT t1.name as district,t2.name as product,t3.price
FROM districts as t1, products as t2, prices as t3
WHERE t3.district = t1.code AND t3.product = t2.code
ORDER BY t1.name;"]
# Exibe os resultados
puts "[format {%-30s} district][format {%-30s} product][format {%10s} price]\n\n"
for {set i 0} {$i < [llength $res]} {incr i} {
    set tuple(district) [lindex [lindex $res $i] 0]
    set tuple(product) [lindex [lindex $res $i] 1]
    set tuple(price) [lindex [lindex $res $i] 2]
    puts "[format {%-30s} $tuple(district)][format {%-30s} $tuple(product)][format {%10s} $tuple(price)]\n"
}
# Disconecta o banco de dados
db disconnect


Implementação 2:

# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados
set user rlsm
database connect db pizza $user
# Cria uma procedure para exibir os resultados
proc showresults {district product price} {
    puts "[format {%-30s} $district][format {%-30s} $product][format {%10s} $price]\n"
}
# Exibe um cabecalho
puts "[format {%-30s} district][format {%-30s} product][format {%10s} price]\n\n"
# Executa a consulta e exibe os resultados
db eval showresults "SELECT t1.name as district,t2.name as product,t3.price
FROM districts as t1, products as t2, prices as t3
WHERE t3.district = t1.code AND t3.product = t2.code
ORDER BY t1.name;"
# Disconecta o banco de dados
db disconnect


Implementação 3:

# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados
set user rlsm
database connect db pizza $user
# Executa a consulta
db statement stmt  "SELECT t1.name as district,t2.name as product,t3.price
FROM districts as t1, products as t2, prices as t3
WHERE t3.district = t1.code AND t3.product = t2.code
ORDER BY t1.name;"
stmt execute
# Exibe os resultados
puts "[format {%-30s} district][format {%-30s} product][format {%10s} price]\n\n"
# tuple e o vetor associativo que contera os valores de cada linha retornada a cada execucao do comando fetch
while {[stmt fetch tuple]} {
    puts "[format {%-30s} $tuple(district)][format {%-30s} $tuple(product)][format {%10s} $tuple(price)]\n"
}
# Disconecta o banco de dados
db disconnect
Os fragmentos de código acima imprimirão no console a tabela abaixo:
 
 
RESULTADO DA CONSULTA
district product price
Arenoso Pizza Média
12.00
Arenoso Pizza Grande
13.90
Arenoso
Pizza Família
17.00
Arenoso Lazanha
13.90
Arenoso Filé
13.90
Arvoredo Pizza Média
12.00
Arvoredo Pizza Grande
13.90
Arvoredo Pizza Família
17.00
Arvoredo Lazanha
13.90
Arvoredo Filé
13.90

Alterando dados das tabelas

# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados
set user rlsm
database connect db pizza $user
# Insere os dados na tabela
db "INSERT INTO districts (code, name) VALUES (\'3\',\'Barbalho\');"
db "SELECT * FROM districts WHERE code = \'3\';"
# Atualiza os dados na tabela
db "UPDATE districts SET name = \'Av. Bete\' WHERE code = \'3\';"
db "SELECT * FROM districts WHERE code = \'3\';"
# Disconect o banco de dados
db disconnect
Apagando dados das tabelas
# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados
set user rlsm
database connect db pizza $user
# Visualizando os dados na tabela
db "SELECT * FROM districts;"
# Apagando os dados da tabela
db "DELETE FROM districts WHERE code = \'3\';"
db "SELECT * FROM districts;"
# Disconect o banco de dados
db disconnect
Criando índices
# Carrega o TclODBC
package require tclodbc
# Conecta o banco de dados
set user rlsm
database connect db pizza $user
# Cria os indices
db "CREATE INDEX districts_idx ON districts(code);"
db "CREATE INDEX products_idx ON products(code);"
db "CREATE INDEX prices_idx ON prices(district, product);"
# Exibe o resultado da consulta
db "SELECT t1.name as district,t2.name as product,t3.price
FROM districts as t1, products as t2, prices as t3
WHERE t3.district = t1.code AND t3.product = t2.code;"
# Disconect o banco de dados
db disconnect
Índices tornam as consultas SQL muito mais rápidas, contudo, alguns RDBMSs, não utilizarão os índices, caso você inclua a cláusula ORDER BY na sua declaração SELECT. Por outro lado, nem todos os DBMSs suportam índices. Assim, se você deseja tornar os seus programas realmente portáveis, não utilize índices, se realmente não precisar deles. Por exemplo, se sua tabela possui poucas linhas( menos de 500 ), não haverá necessidade de se utilizar índices.

Para uma descrição detalhada de todos os comandos disponíveis em uma interface Tcl-RDBMS, consulte a documentação on-line do seu RDBMS. Para uma aula introdutória à linguagem SQL consulte a apostila Programando em SQL disponível para download em http://www.souzamonteiro.com/download_freeware.shtml.

Para maiores informações envie e-mail para info@souzamonteiro.com.


http://www.souzamonteiro.com
info@souzamonteiro.com

Copyright(C) 2000 by Roberto Luiz Souza Monteiro