quarta-feira, 3 de agosto de 2011

Função Oracle PL/SQL para testar se uma string representa um número: isNumber ou isNumeric

TAGs: Oracle, SQL, PL/SQL, isNumber, isNumeric

Não existe uma função para testar se o conteúdo de uma string representa um valor numérico, mas existe um workaround.

LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' ')))

Essa função vai retornar null se o valor for numérico, assim você pode testar com "is null" em uma cláusula where. Por exemplo:

select * from tabela where LENGTH(TRIM(TRANSLATE(campoString, ' +-.0123456789', ' '))) is null

A função translate troca os dígitos por espaços '  '. A função trim remove os espaços. A função length retorna o tamanho da string. Se a string não for numérica, o tamanho será positivo, caso seja numérica, length retornará null.

Fonte: http://www.techonthenet.com/oracle/questions/isnumeric.php

quinta-feira, 9 de junho de 2011

Comandos do vi

    Sintaxe para executar o vi:
    $ vi nome_do_arquivo
    
    Uma vez carregado o arquivo, você pode navegar com as teclas direcionais (up, down, left, right), mas para editar o arquivo é necessário usar os comandos abaixo:
    Observação: Use o ESC para voltar ao modo de comando.
    Comandos básicos de inserção de texto:
    iInsere texto antes do cursor
    aInsere texto depois do cursor
    rInsere texto no início da linha onde se encontra o cursor
    AInsere texto no final da linha onde se encontra o cursor
    oAdiciona linha abaixo da linha atual
    OAdiciona linha acima da linha atual
    Ctrl + hApaga o último caracter
    Comandos básicos de movimentação:
    Ctrl+fMove o cursor para a proxima tela
    Ctrl+bMove o cursor para a tela anterior
    HMove o cursor para a primeira linha da tela
    MMove o cursor para o meio da tela
    LMove o cursor para a ultima linha da tela
    hMove o cursor um caracter a esquerda
    jMove o cursor para a proxima linha
    kMove o cursor para linha anterior
    lMove o cursor um caracter a direita
    wMove o cursor para o inicio da proxima palavra (Ignora a pontuacao)
    WMove o cursor para o inicio da proxima palavra (Nao ignora a pontuacao)
    bMove o cursor para o inicio da palavra anterior (Ignora a pontuacao)
    BMove o cursor para o inicio da palavra anterior (Nao ignora a pontuacao
    0Move o cursor para o inicio da linha atual
    ^Move o cursor para o primeiro caracter nao branco da linha atual
    $Move o cursor para o final da linha atual
    nGMove o cursor para a linha n
    GMove o cursor para a ultima linha do arquivo
    Comandos basicos para localizar texto:
    /palavraBusca pela palavra ou caracter em todo o texto
    ?palavraMove o cursor para a ocorrencia anterior da palavra
    nRepete o ultimo comando / ou ?
    NRepete o ultimo comando / ou ? , na direcao reversa
    Ctrl+gMostra o nome do arquivo, o numero da linha corrente e o total de linhas
    Comandos basicos para alteracao de texto:
    xDeleta o caracter que esta sob o cursor
    dwDeleta a palavra, da posicao atual do cursor ate o final
    ddDeleta a linha atual
    DDeleta a linha a partir da posicao atual do cursor ate o final
    rxSubstitui o caracter sob o cursor pelo especificado em x(é opcional indicar o caracter)
    RxSubstitui a palavra sob o cursor pela palavra indicada em x
    uDesfaz a ultima modificacao
    UDesfaz todas as modificacoes feitas na linha atual
    JUne a linha corrente a proxima
    s:/palavra1/palavra2Substitui a primeira ocorrencia de "palavra1" por "palavra2"
    Comandos para salvar o texto:
    :wqSalva o arquivo e sai do editor
    :w nome_do_arquivoSalva o arquivo corrente com o nome especificado
    :w! nome_do_arquivoSalva o arquivo corrente no arquivo especificado
    :qSai do editor
    :q!Sai do editor sem salvar as alterações realizadas
        Exemplo para abrir um arquivo, adicionar um texto e salvar:
        1 - digite no prompt: vi <nome_do_arquivo>
        2 - tecle "i", quando o cursor estiver no ponto desejado
        3 - digite o texto
        4 - tecle "ESC"
        5 - digite :wq

    quarta-feira, 12 de janeiro de 2011

    Como fazer uma tabela displaytags não ser exibida quando a página é carregada

    Tags: JSP - Struts 2 - AJAX - struts-dojo-tags

    Considerando que você tenha uma tela com campos de filtragem, uma tabela (usando displaytags e AJAX) com os resultados da busca e essa busca seja relacionada a uma tabela com muitos registros.

    Quando a tela for acessada, como nenhum filtro foi especificado, todos os registros da base de dados vão ser mostrados na tabela e isso pode demorar muito.

    Para evitar esse problema você pode mostrar a tabela vazia e deixar parar mostrar os resultados somente depois que o botão de Busca seja acionado.

    Na verdade a solução deste problema não está no diplaytags, mas sim na tag "div" do struts-dojo-tags onde a tabela é apresentada.

    A tag fica assim:


    <sx:div showLoadingText="true" 
            id="gridDivId" 
            href="seusistema/SuaAction" 
            theme="ajax"
            listenTopics="show_grid" 
            formId="frm_demo" 
            executeScripts="true" 
            preload="false">
       Preencha os campos do filtro e depois clique no botão Buscar 
    </sx:div>    


    O pulo do gato aqui é a propriedade "preload", que tem o valor default true. Quando ela é true, ela aciona imediatamente a ajax linkado com a tabela displaytags que realiza a busca.

    O texto dentro da tag div será apresentado no lugar reservado à tabela quando a tela for acessada.

    Referência:
    [1] http://struts.apache.org/2.0.14/docs/dojo-div.html

    terça-feira, 11 de janeiro de 2011

    Como limitar o número de registros retornados em uma consulta SQL

    Tags: SQL, Ansi SQL, TOP, LIMIT, ROWNUM, Oracle, SQL Server

    Não existe uma instrução SQL padronizada para limitar o número de registros retornados em uma consulta, ou seja, cada fornecedor implementa essa funcionalidade do seu jeito.

    Veja um resumo de como fazer isso para alguns fabricantes:


    DB2 -- select * from table fetch first 10 rows only 
    Informix, InterBase/Firebird, SKIP  -- select first 10 * from table 
    Microsoft SQL Server and Access -- select top 10 * from table 
    MySQL, PostgreSQL, SQLite, HSQL/H2 -- select * from table limit 10 
    Oracle -- select * from table where rownum <= 10




    Referências:

    http://stackoverflow.com/questions/595123/is-there-an-ansi-sql-alternative-to-the-mysql-limit-keyword
    http://www.macoratti.net/d250102.htm
    http://www.dougboude.com/blog/1/2006/06/Equivalent-of-SQL-TOP-X-in-Oracle.cfm

    sexta-feira, 7 de janeiro de 2011

    Como externalizar o persistence.xml

    Tags: Java 6 - JEE - Spring 2.5 - Hinernate 3.0

    No persistence.xml é possível configurar, entre outras coisas, a conexão com a base de dados.

    Quando o sistema é entregue ao cliente em um jar ou war, não existe uma maneira trivial de alterar as informações da base de dados, como a string de conexão, o username e o password.

    Para fazer isso o cliente precisaria abrir o jar/war, alterar o persistence.xml e remontar o archive. Como nem sempre o cliente tem um time que saiba fazer isso, pode ser que você queira deixar o persistence.xml fora da pasta META-INF do seu projeto, por exemplo, em um folder de configuração do sistema em qualquer lugar do file system.

    Abaixo segue o trecho a ser configurado no applicationContext.xml:


    <beans ...>


        <bean id="propertyPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
            <property name="ignoreResourceNotFound" value="true"/>
            <property name="locations">
                <list>
                    <value>file:///${CONF_FOLDER}/dataSource.properties</value>
                </list>
            </property>
        </bean>
        
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
           <property name="persistenceXmlLocation" value="file:///${persistence.path}"/>
           <property name="persistenceUnitName" value="persistence-unit"/>
        </bean>
        
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>    
        
        <tx:annotation-driven transaction-manager="transactionManager" />
        
        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
        
        <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
     
        <context:annotation-config />
        
        <context:component-scan base-package="br.com.seupackage.*"/>


    </beans>



    O pulo do gato aqui é a propriedade persistenceXmlLocation do LocalContainerEntityManagerFactoryBean. Com ela você pode especificar que o persistence.xml estará em qualquer lugar do .jar ou do file system [1].

    Para não deixar o caminho do persistence.xml hardcoded e como não é possível usar variável de ambiente nessa propriedade, é possível utilizar o PropertyPlaceholderConfigurer para configurar esse path.


    O arquivo dataSource.properties, que está no folder reprensentado pela variável de ambiente ${CONF_FOLDER}, tem a propriedade persistence.path com o caminho absoluto do persistence.xml.


    O problema estaria resolvido aqui se não fosse um efeito colateral de mudar o persistence.xml de lugar. Quando o persistence.xml não está dentro do jar, o PU root path muda para o jar que iniciou o sistema.

    Se o ponto de entrada do sistema é o jar que possuía o persistence.xml (java -jar seuSistema.jar), não tem problemas.

    Caso o jar ponto de entrada do sistema chame outro jar que é o que possuía o persistence.xml, aí você terá que fazer uma modificação no persistence.xml

    Um exemplo dessa arquiterura é:
    projeto_gui.jar       - ponto de entrada do sistema
    projeto_model.jar  - possui o applicationContext e o persistence

    Veja a modificação no persistence.xml:


    <persistence ...>


    <persistence-unit name='persistence-unit'>


    <provider>org.hibernate.ejb.HibernatePersistence</provider>
            
            <jar-file>file:///C:/seusistema/lib/projeto_model.jar</jar-file>
             
    <properties>
    ...


                <property name="hibernate.connection.provider_class"
                        value="org.hibernate.connection.C3P0ConnectionProvider" />            
    ...
                <property name="hibernate.connection.url" value="jdbc:oracle:thin:@192.168.0.2:1521:base" />
        <property name="hibernate.connection.username" value="user" />  
        <property name="hibernate.connection.password" value="password" />  
    </properties>


    </persistence-unit>


    </persistence>


    A tag <jar-file> foi adicionada para informar que o PU root path (o caminho que este persistence unit deve procurar as classes anotadas como Entity) é o jar que possuía o persistence.xml antes desta alteração.


    Referência:

    [1] LocalContainerEntityManagerFactoryBean: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html#setPersistenceXmlLocation(java.lang.String)

    sexta-feira, 17 de dezembro de 2010

    Por dentro do Component do Information Element (IE) Facility do protocolo DSS1

    Vou registrar o conhecimento adquirido por mim e pelo meu amigo Bruno Oliveira para a posteridade.
     
    Depois de muito bater cabeça entendemos como codificar/decodificar um componente de cabo a rabo.
     
    Vamos usar um exemplo para ficar mais fácil. Vamos decodificar o componente abaixo:
     
    A1-1B-02-02-00-A0-06-06-04-00-82-67-01-08-30-0D-0A-01-00-02-01-00-40-05-04-03-80-90-A3
     
    Component Type
     
    O primeiro octeto é o tipo de componente. Existem quatro tipos de componentes:
    A1 = Invoke
    A2 = Return Result
    A3 = Return Error
    A4 = Reject
     
    No nosso caso o primeiro octeto é A1, então é um Invoke Component.
     
    * [1] capítulo 23.4.1
     
    Component Lenght
     
    A segunda informação a ser extraída é o tamanho do octeto. O lenght pode ser codificado usando 1, 2 ou 3 octetos, de acordo com a tablela abaixo
     
    Tamanho      - Codificação - Octetos usados
    0 a 127        - XX               - Octeto 2
    128 a 255     - 81-XX          - Octeto 2 e 3
    256 a 1023   - 82-XX-XX      - Octeto 2, 3 e 4
     
    Resumindo o quadro:
    * se o segundo octeto do component é 81, o lenght tá no terceiro octeto
    * se o segundo octeto do component é 82, o lenght tá no terceiro e no quarto octeto
    * se o segundo octeto não é nem 81, nem 82, o lenght é o segundo octeto em si
     
    No nosso caso o segundo octeto é 1B, logo o lengh é ele mesmo. 0x1B é 27 em decimal. Pode contar, após o lenght, temos 27 octetos no exemplo.
     
    * [1] capítulo 23.4.1
     
    Tag
     
    A terceira informação é o Tag. Pode ser Tag para Invoke Id ou Tag para NULL (usado em caso de erro)
     
    O Tag para Invoke ID é 02 e para Null é 05.
     
    No nosso caso p terceiro octeto é 02, logo um Tag para Invoke Id.
     
    * [1] capítulo 23.4.1 e 23.4.4
     
    Lenght of Invoke Id
     
    A quarta informação é o tamanho do Invoke Id.
     
    Esse campo é de somente um octeto.
     
    No nosso caso, o quarto octeto é 02, então o tamanho do Invoke Id é de dois octetos.
     
    * [1] capítulo 23.4
     
    Invoke Id
     
    O Invoke Id é divido em quatro faixas:
    A | 0 a 127          | 1 octeto
    B | 128 a 32767   | 2 octeto
    C | -32768 a -129 | 2 octeto
    D | -128 a -1        | 1 octeto
     
    O octetos é sinalizado (o bit mais significativo indica o sinal).
     
    Como já vimos que o tamanho é 2, nosso Invoke Id é 00-A0.
     
    Como o bit mais significativo é 0, sabemos que é Invoke Id da faixa B e seu valor em decimal é 160.
     
    * [1] capítulo 23.1
     
    -----------------------------------------------------------------------------------------------------------------------------------------------------------
    Nesse ponto podemos parar para um café.
     
    Bom, já decodificamos A1-1B-02-02-00-A0
    Ainda falta 06-06-04-00-82-67-01-08-30-0D-0A-01-00-02-01-00-40-05-04-03-80-90-A3
     
    Tomou café? So, let´s go!
    -----------------------------------------------------------------------------------------------------------------------------------------------------------
     
     
    Operation-value
     
    A próxima informação a ser extraída é a operação. Esse informação que define o quê você quer fazer dentro do tipo de componente que você está.
     
    * [1] capítulo 4
     
    Esse campo está codificado segundo o ASN.1 e BER. O tipo de dado utilizado é um CCBSOID, que em grosso modo é uma classe que extende o tipo Object Identifier.
     
    Na codificação BER, é usada uma técnica chamada TLV (Type, Length, Value).
     
    * [2]
     
    Type of Operation-value
     
    Nessa codificação o type é definido no primeiro octeto.
     
    Nosso primeiro octeto é 06:
    0000 0110
    Os bits 8 e 7 são a classe. No nosso caso 00 e significa que o tipo de dados é Universal (conhecido por qq organização).
    O bit 6 é um flag. Quando 0 significa Primitive (tipo de dados primitivo). Quando 1 significa Constructed. Tipo de dados derivado.
    Os bits de 5 a 1 são o Number, que indica que tipo de dado é. No nosso caso é 6, indicando um OBJECT IDENTIFIER.
     
    * [2]
     
    Length of Operation-value
     
    O segundo octeto é o tamanho do tipo de dados. 
    No nosso caso 06, dizendo que o dado está nos próximos 6 octetos.
     
    Content of Operation-value
     
    O OBJECT IDENTIFIER é uma informação de identificação única no mundo. Não existem dois objetos no mundo com o mesmo object identifer.
     
    O registro dos Objects Identifiers fica a cargo da ITU-T. Quando algum maluco prentende definir um objeto que poderá ser conhecido por qq empresa no mundo ele tem que fazer o registro.
     
    * [3]
     
    A codificação de um Object Identifier segue a norma X.209 da CCITT. Essa norma foi substituída pela X.690 da ITU-T.
     
    O Object identifier é uma sequência de números onde cada parte tem seu significado próprio.
     
    Vou usar a notação de pontos para dar um exemplo. o Object Identifier 0.3.2044 deve ser interpretado assim:
     
    O primeiro campo, 0, significa qual é o organismo de padronização. Zero significa CCITT ou ITU-T.
    De acordo com o primeiro campo o segundo campo muda de semântica. Nesse caso o segundo campo, 3, significa network-operator.
    A história se repete. De acordo com o segundo campo, o terceiro tem o seu significado. Nesse caso 2044 significa "NETHERLANDS Unisource / Unidata"
     
    Isso foi só um exemplo de Object Identifier. Agora a gente vai decodificar isso aí.
     
    O OID é uma sequencia de octetos onde os valores são codificados usando apenas 7 bits. O oitavo bit é um indicador que o próximo octeto deve ser usado para ser agrupado com o atual para se chegar no número desejado.
     
    Tem mais um if. As duas primeiras clases são codificadas no primeirto octeto. Assim, no OID X.Y.Z.A.B , as classes X e Y são codificadas no mesmo octeto.
     
    A regra para essa codificação é: (X*40)+Y
     
    * [4] capítulo 22
     
    Vamos trabalhar com o nosso OID 04-00-82-67-01-08
     
    Sabemos que o primeiro octeto, 04, contém duas classes e conhecemos a sua codificação então...
    Extraindo-se os 7 bits continuamos continuamos com 0x04 e 4 em decimal.
    Dividindo por 40 temos o quociente e o resto. O quociente é o X e o resto é o Y.
    Logo nosso OID começa com "0.4".
     
    Vamos para o próximo octeto, 00. No work to do here. Agora temos 0.4.0.
     
    Vamos para o proxímo octeto, 82. Como o bit mais ignificativo está setado a gente tem que pegar o próximo octeto também que é 67.
    Temos que pegar somente os 7 bits de cada um, logo
     
    000 010 e 110 0111, juntando os bits temos: 0000 0001 e 0110 0111 que dá 0x167, 359 em decimal. Agora temos 0.4.0.359.
     
    Ainda temos o 01 e 08, mas esses não exigem esforço e por isso completamos nosso CCBSOID:0.4.0.359.1.8 
     
    O significado dele é CCBSStatusRequest.
     
    * [1] capítulo 22.1.75
    * [5] capítulo 7 table 3
     
    Isso mesmo... Esse trabalho todo para descobrir que a operação a ser realizada é um CCBSStatusRequest.
     
    -----------------------------------------------------------------------------------------------------------------------------------------------------------
    Mais um café?
     
    Bom, já decodificamos A1-1B-02-02-00-A0
    E 06-06-04-00-82-67-01-08
    Ainda falta 30-0D-0A-01-00-02-01-00-40-05-04-03-80-90-A3
     
    Tomou café? So, let´s go!
    -----------------------------------------------------------------------------------------------------------------------------------------------------------
     
    CCBS Status Request
     
    Os campos dessa operação são Recall Mode, CCBS Reference, Q931 Information Element.
    * [1] capítulo 16.1.1 página 153.
    * [5] capítulo 7 table 3
     
    Continuamos seguindo a história do TLV.
     
    O primeiro octeto é 0x30, 0011 0000, logo:
    Class Universal: 0
    Contructed: 1
    Number: 16 = Sequence
     
    O segundo octeto é o tamanho: 0x0D, 13 em decimal.
     
    O CCBSStuatusRequest é 0A-01-00-02-01-00-40-05-04-03-80-90-A3
     
    Recall Mode
     
    Continuamos com o TLV para extrair o RecallMode. O Octeto em questão é o 0x0A, 0000 1010.
    Class Universal: 0
    Primitive: 0
    Number: 10 = Enumerated
     
    O tamanho é 0x01 e o valor é 0x00.
     
    O Recall Mode é um tipo ENUMERATED indicando Global Recall (0) ou Specifica Recall (1). Logo nosso Recall Mode = Global Recall
     
    * [1] capítulo 28.1.88
     
    CCBS Reference
     
    Ok, só falta 02-01-00-40-05-04-03-80-90-A3. Vamos para o CCBS Reference.
     
    O Octeto em questão é o 0x02, 0000 0010.
    Class Universal: 0
    Primitive: 0
    Number: 2 = Integer
     
    O tamanho é 0x01 e o valor é 0x00, logo, CCBS Reference = 0;
     
    Q931 Information Element
     
    O octeto restante é 40-05-04-03-80-90-A3
     
    Continuamos com o TLV. O Octeto em questão é o 0x40, 0100 0000.
    Class Application: 1
    Primitive: 0
    Number: 0 (depende da aplicação, precisamos olhar na ASN.1 do CCBS)
     
    O tamanho é 0x05 e o valor é 04-03-80-90-A3.
     
    Esses 5 octetos representam um IE do DSS1. Agora podemos nos basear na FS do DSS1 da Ericsson [7].
     
    O primeiro octeto é o IE Identifier. 0x04 é o id do Bearer capability.
    O segundo octeto é o lenght, logo temos q analisar 3 octetos.
    O terceiro octeto traz duas informações:
        Coding Standard = 00 = CCITT standardizeted
        Information Transfer Capability = 00000 = Speech
    O quarto octeto também traz duas informações:
       Transfer Mode = 00 = Circuit mode
       Information Transfer Rate = 10000 = 64 kbits
    O quinto, e último, octeto indica o User Information Layer 1 Protocol = Rec. G.711 A-law
     
     
     
    -----------------------------------------------------------------------------------------------------------------------------------------------------------
     
    Referências:
     
     
    1 - Test Component Data Specification
     
    2 - BER: Basic Enconding Rules
     
    3 - Object Identifier Repository
     
    4 - X.209 - Specification of Basic Encoding Rules for Abstract Syntax Notation One (ASN.1)
     
    5 - ETSI EN 300 359-1 v1.3.2 - CCBS Protocol Specification
     
    6 - ETSI EN 300 196-1 v1.3.2 - Generic function protocol for supporting supplementary services, DSS1 - Protocol Specification
     
    7 - DSS1 Layer 3 Protocol Specification 
     
    8 - Der ISDN-D-Kanal

    domingo, 12 de dezembro de 2010

    Como fazer downloads a partir de uma máquina Linux sem interface gráfica

    Apesar de ter trabalhado uns quatro anos com Solaris, não sei fazer muitas coisas usando somente linha de comando.

    Uma das coisas que não nunca havia feito via linha de comando é download na Internet.

    O comando mágico é o wget. Basta passar o link do download como parâmetro para o comando.

    Testei o comando em um CentOS e funcionou muito bem:


    ]# wget http://www.smartfoxserver.com/products/download.php?d=76
    --2010-12-12 13:20:26--  http://www.smartfoxserver.com/products/download.php?d=76
    Resolving www.smartfoxserver.com... 62.149.227.100
    Connecting to www.smartfoxserver.com|62.149.227.100|:80... connected.
    HTTP request sent, awaiting response... 302 Found
    Location: ../download/SFSPRO_linux_1.6.6.tar.gz [following]
    --2010-12-12 13:20:27--  http://www.smartfoxserver.com/download/SFSPRO_linux_1.6.6.tar.gz
    Connecting to www.smartfoxserver.com|62.149.227.100|:80... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 136461484 (130M) [application/x-gzip]
    Saving to: `SFSPRO_linux_1.6.6.tar.gz'


    100%[===================================================================================================================>] 136,461,484  221K/s   in 9m 2s


    2010-12-12 13:29:29 (246 KB/s) - `SFSPRO_linux_1.6.6.tar.gz' saved [136461484/136461484]


    Eu não precisei de nada avançado, mas dá para fazer milagres com o wget, como por exemplo, baixar um site inteiro. Veja mais detalhes na referência [1] .

    Referência:
    [1] http://www.simplehelp.net/2008/12/11/how-to-download-files-from-the-linux-command-line/