- This topic has 2 replies, 2 voices, and was last updated 7 years, 2 months ago by José Laurindo Chiappa.
-
AuthorPosts
-
31 de agosto de 2017 at 4:07 pm #108960viralataParticipant
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 corretamenteIsto saiu totalmente do escopo do meu conhecimento de desenvolvedor
Grato 🙁 🙁 🙁31 de agosto de 2017 at 5:35 pm #108963José Laurindo ChiappaModeratormeu 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
31 de agosto de 2017 at 6:17 pm #108964José Laurindo ChiappaModeratorDois 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.020 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=10Procedimento 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.020 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=8Procedimento 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=14Procedimento 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
-
AuthorPosts
- You must be logged in to reply to this topic.