quarta-feira, 28 de maio de 2008

Utilizando a expressão INTERVAL com o Flashback Query no Oracle

Olá,
Este artigo é um complemento ao artigo Utilizando Flashback Query no Oracle 9i publicado em Maio de 2007 na qual o conteúdo do mesmo abordou a utilização do recurso de flashback query que permite visualizar os dados como eles estavam em um determinado tempo no passado. A dica que deixo aqui, apenas para salientar, é que também podemos utilizar a expressão INTERVAL ao utilizar a cláusula AS OF TIMESTAMP, ou sempre que necessário caso precisarmos utilizar funções de data como SYSDATE, SYSTIMESTAMP, CURRENT_TIMESTAMP, etc. 

SQL> set time on
09:23:14 SQL> create table t1 (id number);

Tabela criada.

09:23:33 SQL> insert into t1 values (1);

1 linha criada.

09:23:40 SQL> insert into t1 values (2);

1 linha criada.

09:23:42 SQL> insert into t1 values (3);

1 linha criada.

09:23:44 SQL> commit;

Validação completa.

09:23:47 SQL> update t1 set id=id*10;

3 linhas atualizadas.

09:27:17 SQL> commit;

Validação completa.

09:27:23 SQL> update t1 set id=id*20;

3 linhas atualizadas.

09:32:21 SQL> commit;

Validação completa.

-- Visão dos dados atuais armazenados na tabela T1
09:32:26 SQL> select * from t1 order by id;

       ID
----------
       200
       400
       600

-- Visão dos dados armazenados na tabela T1 há 5 minutos atrás
09:32:43 SQL> select * from t1
           2  as of timestamp (systimestamp - interval '5' minute) order by id;

       ID
----------
        10
        20
        30

-- Visão dos dados armazendados na tabela T1 há 7 minutos atrás
09:33:44 SQL> select * from t1
           2  as of timestamp (systimestamp - interval '7' minute) order by id;

       ID
----------
         1
         2
         3

Em resumo, podemos obter informações de dados de flashbask desejados entre intervalos de tempo utilizando a expressão INTERVAL:

SQL> select interval '1' year from dual;

INTERVAL'1'YEAR
----------------------------------------
+01-00

SQL> select interval '1' month from dual;

INTERVAL'1'MONTH
----------------------------------------
+00-01

SQL> select interval '1' day from dual;

INTERVAL'1'DAY
----------------------------------------
+01 00:00:00

SQL> select interval '1' hour from dual;

INTERVAL'1'HOUR
----------------------------------------
+00 01:00:00

SQL> select interval '1' minute from dual;

INTERVAL'1'MINUTE
----------------------------------------
+00 00:01:00

SQL> select interval '1' second from dual;

INTERVAL'1'SECOND
----------------------------------------
+00 00:00:01.000000

segunda-feira, 19 de maio de 2008

É possível saber a data de criação de uma ROLE no Oracle?

Olá,

Esta pergunta foi postada recentemente por um membro do Oracle OTN forums na qual o mesmo desejava obter a data de criação de uma role. Em um primeiro momento, poderíamos pensar em consultar a view DBA_ROLES mas a mesma não disponibiliza esta informação. Uma outra view que poderíamos pensar em consultar seria a DBA_OBJECTS, mas esta view não possui nenhuma informação relacionada a roles de banco de dados. Embora o Oracle não possua nenhuma view de dicionário de dados que se possa consultar para obter esta informação, ainda sim poderemos obte-la consultando a tabela base do dicionário de dados chamada USER$. Esta tabela base é utilizada pela view de dicionário de dados DBA_USERS normalmente consultada para obtenção de informações de usuários existentes no banco de dados. Na verdade, a tabela base USER$ possui uma coluna TYPE$ na qual armazena um valor de tipo. O valor [1] está associado para usuários de banco de dados e o tipo [2] para roles de banco de dados. Neste caso, como sabemos que a view DBA_USERS possui uma coluna chamada CREATED (baseada na coluna CTIME da USER$) utilizada para armazenar a data de criação de um usuário, poderemos também verificar a data de criação de uma role, acessando diretamente a tabela base USER$ como demonstrado no exemplo abaixo:
-- Criando uma role de teste
SQL> create role myrole;

Função criada.

-- Obtendo informação de data de criação da role
SQL> select name,to_char(ctime,'dd/mm/yyyy hh24:mi:ss') ctime
 2  from user$ where name='MYROLE';

NAME                            CTIME
------------------------------- -------------------
MYROLE                          19/05/2008 13:45:42

-- verificando que a tabela base user$ é de propriedade do usuário SYS
SQL> select owner,object_name,object_type from dba_objects
 2  where object_name="USER$"

OWNER               OBJECT_NAME                         OBJECT_TYPE
------------------- ----------------------------------- -------------------
SYS                 USER$                               TABLE

-- Listando as colunas da tabela USER$
SQL> desc USER$
Nome                                      Nulo?    Tipo
----------------------------------------- -------- ----------------------------
USER#                                     NOT NULL NUMBER
NAME                                      NOT NULL VARCHAR2(30)
TYPE#                                     NOT NULL NUMBER
PASSWORD                                           VARCHAR2(30)
DATATS#                                   NOT NULL NUMBER
TEMPTS#                                   NOT NULL NUMBER
CTIME                                     NOT NULL DATE
PTIME                                              DATE
EXPTIME                                            DATE
LTIME                                              DATE
RESOURCE$                                 NOT NULL NUMBER
AUDIT$                                             VARCHAR2(38)
DEFROLE                                   NOT NULL NUMBER
DEFGRP#                                            NUMBER
DEFGRP_SEQ#                                        NUMBER
ASTATUS                                   NOT NULL NUMBER
LCOUNT                                    NOT NULL NUMBER
DEFSCHCLASS                                        VARCHAR2(30)
EXT_USERNAME                                       VARCHAR2(4000)
SPARE1                                             NUMBER
SPARE2                                             NUMBER
SPARE3                                             NUMBER
SPARE4                                             VARCHAR2(1000)
SPARE5                                             VARCHAR2(1000)
SPARE6                                             DATE

De acordo com a estrutura da tabela USER$ listada acima, podemos notar também a existência de uma coluna chamada PTIME. Esta coluna tem como objetivo armazenar a data de alteração de senha de um usuário de banco de dados. Normalmente esta informação é útil quando um perfil é criado e atribuído para os usuários de banco de dados. Caso os parâmetros PASSWORD_REUSE_TIME e/ou PASSWORD_REUSE_MAX sejam setados neste perfil, então será possível consultar a tabela de dicionário de dados USER_HISTORY$ para verificar, caso necessário, o histórico de modificações de senha de um usuário.

-- Criando um usuário para teste
SQL> create user myuser identified by myuser;

Usuário criado.

SQL> select
 2    name,
 3    to_char(ctime,'dd/mm/yyyy hh24:mi:ss') ctime,
 4    to_char(ptime,'dd/mm/yyyy hh24:mi:ss') ptime
 5  from
 6    user$
 7  where name='MYUSER';

NAME            CTIME               PTIME
--------------- ------------------- -------------------
MYUSER          19/05/2008 13:50:25 19/05/2008 13:50:25


-- Aguardando um tempo ...

-- Alterando a senha do usuárioSQL> alter user myuser identified by legatti;

Usuário alterado.

SQL> select
 2    name,
 3    to_char(ctime,'dd/mm/yyyy hh24:mi:ss') ctime,
 4    to_char(ptime,'dd/mm/yyyy hh24:mi:ss') ptime
 5  from
 6    user$
 7  where name='MYUSER';

NAME            CTIME               PTIME
--------------- ------------------- -------------------
MYUSER          19/05/2008 13:50:25 19/05/2008 13:53:08

quarta-feira, 7 de maio de 2008

Um pouco do Oracle SQL Developer ...

Olá,


 

Para os fãs do velho e bom SQL*PLUS, TOAD (uso comercial, mas possui versão gratuita com limitações) e PL/SQL DEVELOPER (uso comercial e versão de avaliação para 30 dias), quem ainda não conhece o Oracle SQL Developer, vale apena baixa-lo e utilizá-lo. Esta ferramenta gráfica gratuita da Oracle que teve seu projeto iniciado em 2006 é voltada não somente para desenvolvedores, mas também para administradores de banco de da dados. Atualmente, o Oracle SQL Developer 1.5 é certificado para rodar não só nas versões dos bancos de dados Oracle 9i (9.2.0.1), 10g, 11g, mas também dá suporte para conexão com os bancos de dados MySQL, SQL Server, Sybase e Access, e como esta ferramenta é desenvolvida em Java, a mesma pode ser executada nas plataformas Windows, Linux e Mac OS X.

Pelo fato do software utilizar um driver JDBC, não é necessário que seja feito nenhuma instalação Client da Oracle, ou seja, é necessário apenas baixar o arquivo compactado (.zip) do site da Oracle, descompactá-lo em um diretório e no caso do Windows, criar um atalho para o executável (sqldeveloper.exe). Vale a pena salientar que é disponibilizado para download uma versão com e sem o Java, mas para não ter erro você pode baixar a versão completa. Por ter uma interface gráfica, o Oracle SQL Developer facilita a navegação pelos objetos do banco de dados (tabelas, views, procedures, contraints, etc...), além de permitir a criação, edição, exclusão e visualização dos códigos fontes não só dos objetos, mas também de usuários de banco de dados. Neste caso, o usuário logado deverá ter as devidas permissões para poder criar e/ou dropar um usuário de banco de dados.

Uma outra função importante que ele nos oferece é a de permitir a geração dos planos de execução dos SQL's submetidos, além de permitir debugar scritps PL/SQL.


Algumas das capacidades do Oracle SQL Developer

01) Criar conexões com bancos de dados
02) Navegar entre os objetos
03) Criar objetos
04) Modificar Objetos
05) Consultar e manipular dados dos objetos (DML)
06) Exportar e importar dados / Gerar DDL dos objetos
07) Efetuar cópia e comparações entre schemas e objetos
08) Processar comandos
09) Editar código PL/SQL
10) Executar e debugar códigos PL/SQL
11) Executar e criar relatórios personalizados

12) Facilitar a migração inter-bancos (Migration Workbench integrado)
13) Permitir integração com sistemas de controle de versão (CVS, Subversion)


Janela Principal do Oracle SQL Developer
 
A documentação completa do Oracle SQL Developer pode ser encontrada facilmente no site do produto, mas eu aconselho também caso possível, assistir as demonstrações on-line oferecidas pela Oracle sobre as capacidades desta ferramenta:

Demonstrações On-line

* Características do Oracle SQL Developer
* Criando uma conexão de banco de dados
* Adicionando uma nova tabela
* Adicionando dados a uma tabela
* Gerando um relatório
* Carregando, executando e debugando código PL/SQL

segunda-feira, 5 de maio de 2008

Cuidado ao manipular objetos do dicionário de dados do Oracle

Olá,
Recentemente um membro do Forum OTN da Oracle postou uma questão relacionada à tabela SYS.DUAL do dicionário de dados e perguntou se existe algum impacto para o banco de dados se a mesma for dropada. Bom, o que me chamou a atenção foi a resposta de um outro membro dizendo que não há impacto nenhum para o banco de dados se a mesma for dropada, e logo após, recriada. Isto é um grande erro porque por qualquer que seja o motivo, os objetos do dicionário de dados jamais deverão ser tocados (alterados com comandos DML/DDL), salvo por aconselhamento e supervisão direta do suporte técnico da Oracle, já que qualquer alteração inadequada nestes objetos poderão resultar em um problema sério no funcionamento do banco de dados ou até mesmo ocasionar um "crash" que impossibilite o "startup" do mesmo. Neste artigo irei mostrar o quanto é perigoso "brincar" com as tabelas de propriedade do usuário SYS, simulando a exclusão da tabela DUAL.
C:\>sqlplus / as sysdba

SQL*Plus: Release 10.2.0.1.0 - Production on Sex Mai 2 14:17:07 2008

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Conectado a:
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production

SYS@XE> desc dual;
Nome                            Nulo?    Tipo
------------------------------- -------- ----------------------------
DUMMY                                    VARCHAR2(1)

SYS@XE> drop table dual;

Tabela eliminada.

SYS@XE> shutdown
Banco de dados fechado.
Banco de dados desmontado.
Instância ORACLE desativada.

SYS@XE> startup
Instância ORACLE iniciada.

Total System Global Area  188743680 bytes
Fixed Size                  1286460 bytes
Variable Size              96472772 bytes
Database Buffers           88080384 bytes
Redo Buffers                2904064 bytes
Banco de dados montado.
ORA-01092: instância ORACLE finalizada. Desconexão forçada

-- Conteúdo do arquivo de log de alerta
Fri May 02 14:21:26 2008
Errors in file c:\oraclexe\app\oracle\admin\xe\udump\xe_ora_3348.trc:
ORA-01775: loop na cadeia de sinônimos

-- Conteúdo do arquivo de rastreamento
Dump file c:\oraclexe\app\oracle\admin\xe\udump\xe_ora_3348.trc
Fri May 02 14:21:25 2008
ORACLE V10.2.0.1.0 - Production vsnsta=0
The following information may aid in finding
the errors which cause the deadlock:
ORA-04020: detectado um conflito durante a tentativa de bloquear o objeto SYS.DUAL

SYS@XE> shutdown abort
ORA-24324: handle de serviços não inicializado
ORA-01041: erro interno: a extensão hostdef não existe
SYS@XE> exit
Desconectado de Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production

Podemos perceber que após a exclusão da tabela SYS.DUAL, O banco de dados ficou impossibilitado de abrir gerando o erro ORA-01092. E agora, como resolver o problema? Bem, sabemos que as tabelas-base do dicionário de dados são criadas automaticamente quando o servidor Oracle executa o script sql.bsq durante a criação do banco de dados através do comando CREATE DATABASE, então será necessário capturar deste arquivo os comandos DDL para recriar tabela DUAL. A questão é como recriar a tabela DUAL se o banco de dados está incapacitado de ser aberto? A dica é setar o parâmetro replication_dependency_tracking no arquivo de inicialização da instância para FALSE.

-- Verificando o conteúdo do script sql.bsq
C:\oraclexe\app\oracle\product\10.2.0\server\RDBMS\ADMIN>findstr /c:"dual" sql.bsq
rem   ssamu      09/28/95 -  dual object number phase 2
rem   ssamu      09/20/95 -  dual object number - cleanup
rem   ssamu      09/18/95 -  dual object numbers
rem   ssamu      09/12/95 -  dual object numbers
create table dual                   /* pl/sql's standard pckg requires dual. */
(dummy varchar2(1))    /* note, the optimizer knows sys.dual is single row */
insert into dual values('X')
create public synonym dual for dual
grant select on dual to public with grant option

-- Alterando o parâmetro replication_dependency_tracking para FALSE
C:\>sqlplus / as sysdba

SQL*Plus: Release 10.2.0.1.0 - Production on Sex Mai 2 14:32:07 2008

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Conectado a uma instância inativa.

SYS@XE> startup nomount
Instância ORACLE iniciada.

Total System Global Area  188743680 bytes
Fixed Size                  1286460 bytes
Variable Size              96472772 bytes
Database Buffers           88080384 bytes
Redo Buffers                2904064 bytes

SYS@XE> alter system set replication_dependency_tracking = FALSE scope=spfile;

Sistema alterado.

SYS@XE> shutdown
ORA-01507: banco de dados não montado

Instância ORACLE desativada.

-- Executando o script para recriar a tabela SYS.DUAL
SYS@XE> startup
Instância ORACLE iniciada.

Total System Global Area  188743680 bytes
Fixed Size                  1286460 bytes
Variable Size              96472772 bytes
Database Buffers           88080384 bytes
Redo Buffers                2904064 bytes
Banco de dados montado.
Banco de dados aberto.

SYS@XE> create table dual
2    (dummy varchar2(1))
3    storage (initial 1)
4  /

Tabela criada.

SYS@XE> insert into dual values('X')
2  /

1 linha criada.

SYS@XE> create public synonym dual for dual
2  /
create public synonym dual for dual
               *
ERRO na linha 1:
ORA-00955: nome já está sendo usado por um objeto existente


SYS@XE> grant select on dual to public with grant option
2  /

Concessão bem-sucedida.

-- Alterando o parâmetro replication_dependency_tracking para o seu valor padrão
SYS@XE> alter system set replication_dependency_tracking = TRUE scope=spfile;

Sistema alterado.

SYS@XE> shutdown
Banco de dados fechado.
Banco de dados desmontado.
Instância ORACLE desativada.

-- Verificando se o problema foi resolvido
SYS@XE> startup
Instância ORACLE iniciada.

Total System Global Area  188743680 bytes
Fixed Size                  1286460 bytes
Variable Size              96472772 bytes
Database Buffers           88080384 bytes
Redo Buffers                2904064 bytes
Banco de dados montado.
Banco de dados aberto.

SYS@XE> select * from dual;

D
-
X


Em resumo, jamais pense em dropar qualquer objeto de propriedade do usuário SYS.