![]() |
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 tclodbcEu 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:
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:
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:
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:
|
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 |
|
code
|
name |
|
1
|
Pizza Média |
|
2
|
Pizza Grande |
|
3
|
Pizza Família |
|
4
|
Lazanha |
|
5
|
Filé |
|
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 disconnectInserindo 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 disconnectVisualizando 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 disconnectOs fragmentos de código acima imprimirão no console a tabela abaixo:
| 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 disconnectApagando 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 disconnectCriando í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 |
Copyright(C) 2000 by Roberto Luiz Souza Monteiro