Tipos de Dados SQL 1. SQL-92 O padrão SQL-92 define um conjunto de tipos de dados que não são mapeados bijetivamente com os tipos de dados Java. As aplicações que movem dados de SQL para Java e vice versa devem levar em consideração a maneira pela qual JDBC trata esse mapeamento. É necessário conhecer como um tipo de dados Java recebe uma representação SQL e vice versa. Quando se recuperar dados de uma fonte de dados JDBC, a implementação do ResultSet fará o mapeamento dos tipos de dados SQL em tipos de dados Java. A tabela que se segue exibe uma correspondência entre tipos de dados SQL e tipos de dados Java. 1 Tipo de Dados SQL CHAR VARCHAR LONGVARCHAR NUMERIC DECIMAL BIT TINYINT SMALLINT INTEGER BIGINT REAL FLOAT DOUBLE BINARY VARBINARY LONGVARBINARY DATE TIME TIMESTAMP Tipo de Dados Java String String String Java.math.BigDecimal Java.math.BigDecimal boolean byte short int long float double double byte[] byte[] byte[] java.sql.Date java.sql.Time java.sql.Timestamp De maneira oposta a correspondência entre tipos de dados Java e tipos de dados SQL pode ser vislumbrada abaixo. 2 Tipo de Dados Java String Java.math.BigDecimal boolean byte short int long float double byte[] java.sql.Date java.sql.Time java.sql.Timestamp Tipo de Dados SQL VARCHAR, LONGVARCHAR NUMERIC BIT TINYINT SMALLINT INTEGER BIGINT REAL DOUBLE VARBINARY, LONGVARBINARY DATE TIME TIMESTAMP Os tipos de dados iniciados por “Java.” Não são tipos elementares de dados mas classes que possuem métodos de tradução dos dados para formatos utilizáveis. Estas classes são necessárias porque não existe nenhum tipo primitivo de dados que seja mapeado diretamente em um tipo SQL correspondente. Deve-se criar essas classes sempre que for necessário armazenar dados de um banco de Dados 3 2. Novos tipos SQL 2.1 Nomenclatura A próxima versão do padrão ANSI/ISO SQL é chamada de SQL3 e está em fase de apreciação. A API JDBC 2.0 incorpora um modelo dos tipos de dados SQL3 que inclui apenas as propriedades essenciais à troca de dados entre as aplicações e os bancos de dados. A especificação SQL3 prevê a existência dos seguintes tipos de dados: Tipos de dados herdados da SQL2 Char Float Date Etc. Novos tipos BLOB CLOB Tipos estruturados tais como CREATE TYPE PONTO_DE_PLANO (X FLOAT, Y FLOAT) Tipos distintos baseados na representação de primitivos, tais como CREATE TYPE DINHEIRO AS NUMERIC (10,2) Tipos construídos em função dos primitivos tais como REF (tipo estruturado) Tipo base ARRAY [m] Tipos LOCATOR tais como LOCATOR (tipo estruturado) LOCATOR (array) LOCATOR (blob) LOCATOR (clob) 4 Um valor REF é persistente e denota uma instância de um tipo estruturado que reside no banco de dados. Um LOCATOR existe apenas no ambiente do cliente e é um ponteiro lógico para dados que residem no servidor de BD. Um LOCATOR refere-se a dados muito grandes para se materializarem no cliente, tais como áudio e vídeo. Existem operadores definidos ao nível de SQL que recuperam aleatoriamente partes dos dados denotados pelo LOCATOR. 2.2 Blobs e clobs Binary large objects (blobs) e Character large objects (clobs) são tipos de dados tratados de maneira semelhante aos tipos embutidos JDBC. Por default os objetos blob e clob só se mantém validos durante a transação que os criou. Contudo JDBC pode alterar isso, para a duração da sessão, por exemplo. Blob blob = rs.getBlob()1 ; // coluna 1 Clob clob = rs.getClob()1 ; // coluna 2 2.3 Arrays A recuperação de “arrays” pode ser feita pelo método getArray() e o armazenamento pode ser feito por PreparedStatement.setObject(). Array a = rs.getArray(1); // coluna 1 2.4 REF Uma referência SQL pode ser recuperada pelo método getRef() das interfaces ResulSet e CallableStatement. O armazenamento pode ser feito por PreparedStatement.setRef(). Ref ref = rs.getRef(1); 5 2.5 Tipos distintos Um dado SQL do tipo DISTINCT, por default pode ser recuperado por qualquer método getXXX() do tipo subjacente ou original. Se, por exemplo, tivesse ocorrido a definição do tipo DINHEIRO que se segue, sua recuperação seria a indicada e o armazenamento seria da forma PreparedStatement.setXXX() ou PreparedStatement.setBigDecimal(). . CREATE TYPE DINHEIRO AS NUMERIC (10,2) Java.math.BigDecimal bd = rs.getBigDecimal(1); 2.6 Tipos estruturados O valor de uma dado SQL do tipo estruturado sempre é recuperado pelo método getObject(), que, por default, reorna um balor do tipo Struct para um tipo estruturado. O armazenamento pode ser feito por PreparedStatement.Object Struct struct = (Struct)rs.getObject(1); 6 3. Personalização de tipos SQL 3.1 O mapeamento de tipos Uma instância de java.util.Map é usada para manter um mapeamento personalizado entre tipos estruturados SQL definidos pelo usuário e tipos e classes Java. Este objeto (instância) é chamado type-map. Um objeto type-map implementa uma função dos nomes SQL definidos pelo usuário em objetos do tipo java.lang.Class. Um objeto type-map determina a classe da qual construir um objeto para conter dados de um tipo SQL definido pelo usuário. Cada conexão JDBC possui um objeto type-map associado. O objeto type-map contém mapeamento de tipos para a tradução de dados de tipos SQL definidos pelo usuário em operações nessa conexão. São fornecidos métodos para obter e estabelecer um type-map de conexão. Por exemplo java.util.Map map = con.getTypeMap(); con.setTypeMap (map); O primeiro comando recupera um objeto type-map e o segundo comando estabelece um novo mapeamento. Se um tipo de mapeamento para uma conexão não for inicializado pala aplicação JDBC então o mapeamento default é usado nas operações da conexão 3.2 Convenções de classe Java Uma classe Java que aparece em um type-map personalizado deve implementar uma nova interface java.sql.SQLData. A interface SQLData contém métodos que convertem instâncias de tipos SQL definidos pelo usuário em instâncias de classes Java e vice versa tais como SQLData.readSQL() e SQLDtat.writeSQL(). 7 3.3 “Streams” de dados SQL Quando dados de tipos SQL distintos e estruturados são recuperados de um BD, eles retornam em um “stream” implementando a interface SQLInput. Considere-se um objeto SQLData contendo três campos persistentes, um String s, um Bolb blob e um Empregado emp. this.str = sqlin.readString(); this.blob = sqlin.readBlob(); this.emp = (Empregado)sqlin.readObject(); e ainda sqlout.writeString(this.str); sqlout.writeBlob(this.blob); sqlout.writeObject(this.emp); 8