Pular para o conteúdo
  • This topic has 2 replies, 2 voices, and was last updated 7 years, 2 months ago by Avatar photoJosé Laurindo Chiappa.
Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #108960
    Avatar de viralataviralata
    Participant

      Ola

      Tenho uma procedure que executa dinamicamente um códgio (na verdade constroi uma outra procedure), esta procedure é igual em todos clientes e em todos funciona corretamente, mas há um cliente que está reclamando que quando executa dá o seguinte erro:

      ORA-06502: PL/SQL: erro: character string buffer too small numérico ou de valor

      Informaram-me que ele pode estar com uma configuração diferente no NLS_LENGTH_SEMANTICS
      , na empresa onde trabalho o DBA disse que se a tabela de caracteres dele for UTF8 ele deve usar NLS_LENGTH_SEMANTICS como CHAR, o cliente disse que o NLS_LENGTH_SEMANTICS dele é BYTE , mas da sessão é CHAR . Como não sou DBA isto tudo para mim é uma sopa de letras, o que posso fazer para tentar resolver meu problema , ja que as procedures são as mesmas em todo lugar e funcionam corretamente

      Isto saiu totalmente do escopo do meu conhecimento de desenvolvedor
      Grato 🙁 🙁 🙁

      #108963
      Avatar photoJosé Laurindo Chiappa
      Moderator

        meu caro : primeira coisa, SENDO ou NÃO DBA, é ** Obrigação ** de um profissional de TI minimamente qualificado conhecer a lógica de funcionamento de um computador no que se refere á codificação de dados (tipo como expus em https://jlc1967.wordpress.com/2015/02/25/nls-acentuacao-e-outros-misterios-de-localizacao-no-rdbms-oracle/), ** E ** além disso se vc desenvolve aplicações num database Oracle, vc *** TEM *** que conhecer alguns Conceitos básicos do database Oracle, não só os gerais documentados em https://docs.oracle.com/cd/E11882_01/server.112/e40540/toc.htm MAS também os conceitos diretamente relacionados com DESENVOLVIMENTO, listados em http://docs.oracle.com/cd/E11882_01/server.112/e40540/cncptdev.htm#CNCPT7655 : nestes últimos estão SIM documentados os conceitos de GLOBALIZAÇÃO, que pelo que vc diz estão DIRETAMENTE RELACIONADOS à sua issue…. SEM esses conhecimentos sorry, mas vc não avançará muito, não subirá de classe na profissão… SE vc não entender o que é um BYTE, o PORQUE de poderem existir caracteres que ocupam MAIS de um byte e coisas assim, cedo ou tarde vc vai ter DIVERSOS problemas, EM ESPECIAL nos dias de hoje, em que a China e países orientais mandam e desmandam na economia mundial, que teus Clientes fatalmente VÂO TER QUE armazenar dados em alfabetos não-ocidentais…

        Isto posto, a sua resposta : o seu DBA até está certo quando fala de NLS_SEMANTICS mas isso tem mais a ver com TABELAS (https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:127933400346891255 exemplifica) , E além disso teu código NÂO DEVERIA depender se setting de banco, né não ??
        No seu caso específico, vc está falando de CÓDIGO, então o seu problema deve ser VARIÁVEL STRING que vc delimitou com um número X de BYTES e a tal variável está recebendo caracteres que consomem mais de um byte, E vc erradamente Não Previu Isso….
        A solução é vc fazer o DEBUG, encontrar a(s) variáveis que estão recebendo caracteres multibyte e OU aumentar elas OU vc mandar o RDBMS reservar CARACTERES e não BYTES …. Por exemplo, no código abaixo :

        DECLARE
        x varchar2(30);

        ==> O default para vc delimitar tamanhos de variáveis é em BYTES, então o código acima está reservando 30 BYTES de espaço para a variável X : para databases que só trabalham com alfabetos europeus-ocidentais blz, todo caracter ocupa no máximo um byte, vc poderá receber até 30 caracteres nessa variável X…. Isso porém é um *** BUG *** no seu código, vc está SUPONDO que seus clientes/usuários NUNCA vão ter que trabalhar com dados não europeu-ocidentais, o que é um ERRO, como eu disse antes, por causa da GLOBALIZAÇÃO que vivemos… Nesse exemplo, supondo por exemplo que o banco que está rodando teu código está configurado para UTF/UNICODE (onde cada caracter ocupa DOIS BYTES), pra poder guardar 30 caracteres OU vc define a variável X como 60 bytes OU (o melhor imho) vc define a variável especificamente para ser limitada a 30 CARACTERES, independente da qtdade de bytes que esses 30 caracteres ocupem… Isso se faz assim :

        DECLARE
        x varchar2(30 CHAR);

        OK ??

        []s

        Chiappa

        #108964
        Avatar photoJosé Laurindo Chiappa
        Moderator

          Dois pontos adicionais :

          a. quem diz que conhecimento sobre Codificação de caracteres, funcionamento lógico de computador e quejandos é ** Básico ** pra qualquer desenvolvedor não sou eu, o DBA, nem a Oracle, nem a Microsoft : os próprios GURUS do desenvolvimento do software como o Joel Spolsky dizem isso, veja https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/ … Notar que ele NEM ESTÁ DESENVOLVENDO diretamente em bancos de dados (ele programa em PHP e WEB/HTML), então SEM DESCULPAS possíveis…

          b. exemplinho prático da coisa :

          ==> banco com codificação de caracteres em um alfabeto ocidental (o WE é de Western Europe) :

          SQL> select * from NLS_DATABASE_PARAMETERS;

          PARAMETER VALUE


          NLS_LANGUAGE AMERICAN
          NLS_TERRITORY AMERICA
          NLS_CURRENCY $
          NLS_ISO_CURRENCY AMERICA
          NLS_NUMERIC_CHARACTERS .,
          NLS_CHARACTERSET WE8MSWIN1252
          NLS_CALENDAR GREGORIAN
          NLS_DATE_FORMAT DD-MON-RR
          NLS_DATE_LANGUAGE AMERICAN
          NLS_SORT BINARY
          NLS_TIME_FORMAT HH.MI.SSXFF AM
          NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
          NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
          NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
          NLS_DUAL_CURRENCY $
          NLS_COMP BINARY
          NLS_LENGTH_SEMANTICS BYTE
          NLS_NCHAR_CONV_EXCP FALSE
          NLS_NCHAR_CHARACTERSET AL16UTF16
          NLS_RDBMS_VERSION 11.2.0.3.0

          20 linhas selecionadas.

          SQL>

          ==> reservo 10 bytes pra variável, como o caracterset é single-byte, 10 caracteres ocupam 10 bytes não importando se são especiais/acentuados ou não :

          system@O11gR2:SQL> DECLARE
          2 x varchar2(10) := ‘ÁÈÌÓÚFGHIJ’;
          3 BEGIN
          4 dbms_output.put_LINE(‘String X=’ || X || ‘ , tamanho em bytes=’ || lengthb(x));
          5* END;
          system@O11gR2:SQL> /
          String X=ÁÈÌÓÚFGHIJ , tamanho em bytes=10

          Procedimento PL/SQL concluído com sucesso.

          system@O11gR2:SQL>

          ==> banco com codificação UNICODE :

          SYSTEM:@XE:SQL>select * from NLS_DATABASE_PARAMETERS;

          PARAMETER VALUE


          NLS_LANGUAGE AMERICAN
          NLS_TERRITORY AMERICA
          NLS_CURRENCY $
          NLS_ISO_CURRENCY AMERICA
          NLS_NUMERIC_CHARACTERS .,
          NLS_CHARACTERSET AL32UTF8
          NLS_CALENDAR GREGORIAN
          NLS_DATE_FORMAT DD-MON-RR
          NLS_DATE_LANGUAGE AMERICAN
          NLS_SORT BINARY
          NLS_TIME_FORMAT HH.MI.SSXFF AM
          NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
          NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
          NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
          NLS_DUAL_CURRENCY $
          NLS_COMP BINARY
          NLS_LENGTH_SEMANTICS BYTE
          NLS_NCHAR_CONV_EXCP FALSE
          NLS_NCHAR_CHARACTERSET AL16UTF16
          NLS_RDBMS_VERSION 11.2.0.2.0

          20 linhas selecionadas.

          SYSTEM:@XE:SQL>

          ==> vou tentar enfiar nesses 10 bytes uma string que contém caracteres multibyte, ó teu erro aqui :

          SYSTEM:@XE:SQL>DECLARE
          2 x varchar2(10) := ‘ÁÈÌÓÚFGHIJ’;
          3 BEGIN
          4 dbms_output.put_LINE(‘String X=’ || X || ‘ , tamanho em bytes=’ || lengthb(x));
          5 END;
          6 /
          DECLARE
          *
          ERRO na linha 1:
          ORA-06502: PL/SQL: erro: buffer de string de caracteres pequeno demais numérico ou de valor
          ORA-06512: em line 2

          ==> vou mostrar que os caracteres estão SIM ocupando mais de um byte :

          SYSTEM:@XE:SQL>DECLARE
          2 x varchar2(10) := ‘ÁÈÌÓ’;
          3 BEGIN
          4 dbms_output.put_LINE(‘String X=’ || X || ‘ , tamanho em bytes=’ || lengthb(x));
          5* END;
          SYSTEM:@XE:SQL>/
          String X=ÁÈÌÓ , tamanho em bytes=8

          Procedimento PL/SQL concluído com sucesso.

          SYSTEM:@XE:SQL>

          ==> SACOU ??? 4 caracteres especiais codificados em UNICODE ocupam 8 bytes…. Aplicando a ** CORREÇÃO ** no TEU bug :

          SYSTEM:@XE:SQL>DECLARE
          2 x varchar2(10 CHAR) := ‘ÁÈÌÓabcdef’;
          3 BEGIN
          4 dbms_output.put_LINE(‘String X=’ || X || ‘ , tamanho em bytes=’ || lengthb(x));
          5* END;
          SYSTEM:@XE:SQL>/
          String X=ÁÈÌÓabcdef , tamanho em bytes=14

          Procedimento PL/SQL concluído com sucesso.

          SYSTEM:@XE:SQL>

          ==> VIU ??? A variável conseguiu guardar os 10 caracteres que eu precisava, mesmo a string ocupando mais de 10 bytes… E a razão dos 4 bytes a maissão JUSTAMENTE os 4 caracteres especiais codificados em UNICODE…

          C.Q.D. ….

          []s

          Chiappa

        Viewing 3 posts - 1 through 3 (of 3 total)
        • You must be logged in to reply to this topic.
        plugins premium WordPress