FW: Problema insolucionável?

506 views
Skip to first unread message

hugo emanoel borges

unread,
Sep 22, 2011, 1:36:12 PM9/22/11
to ph...@googlegroups.com

Pessoal,

Lanço um desafio aqui para que utiliza o Zend Framework. Aqui na empresa utilizamos o Oracle 9i com charset ISO e as aplicações estão desenvolvidas em UTF8. Realizo a conexão lançando o charset UTF8 e tudo fica nas mil maravilhas, exceto em situações específicas. Vou colar aqui um post parecido que foi colocado na página do PHP relatando esse bug no PDO.


- Table for test
CREATE TABLE mytable (col1 NVARCHAR2(20));

- Test data
INSERT INTO mytable VALUES('12345678901234567890'); /* 20 signle byte char */
INSERT INTO mytable VALUES('あいうえおかきくけこさしすせそたちつてと'); /* 20 double byte char, Japanese */

- Test Program
<?php
    print "NLS_LANG=".getenv('NLS_LANG')."\n\n";

    $db = new PDO("oci:dbname=//instance1.cf9klgqzy0gu.ap-northeast-1.rds.amazonaws.com:3306/mydb;charset=AL32UTF8", "user", "pass");
    $db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
    $stmt = $db->prepare("SELECT * FROM mytable");
    $stmt->execute();
    var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
?>
- Test Program Output
# php ocitest.php 
  
NLS_LANG=Japanese_Japan.AL32UTF8


Warning: PDOStatement::fetchAll(): column 0 data was too large for buffer and was truncated to fit it in /root/ocitest.php on line 9
array(2) {
  [0]=>
  array(1) {
    ["COL1"]=>
    string(20) "12345678901234567890"
  }
  [1]=>
  array(1) {
    ["COL1"]=>
    string(40) "あいうえおかきくけこさしす
  }
}


Acontece que o buffer é criado com uma quantidade de bytes específico e os acentos e caracteres especiais utilizam uma quantidade maior de bytes para armazenar. O PHP realiza um TRUNC no valor quando o buffer é estourado. Alguém tem alguma noção de como resolver isso? Já queimei muito fosfato aqui e n saí do lugar.


Help?







Klaus Silveira

unread,
Sep 22, 2011, 1:39:14 PM9/22/11
to ph...@googlegroups.com
Cara, talvez tu já tenha até dado uma olhada, mas a extensão Multibyte String pode te ajudar: 

hugo emanoel borges

unread,
Sep 22, 2011, 1:54:50 PM9/22/11
to ph...@googlegroups.com
Creio que não teria como contornar dessa forma. O problema só acontece em requisições. Consigo salvar dados sem problemas.

Consigo realizar a consulta utilizando o charset default, que é o ISO, e na exibição dos dados utilizar a função utf8_encode(), mas imagine o custo operacional. Após muito tempo pesquisando consegui encontrar uma "solução permanentemente temporária". A Zend já implementou isso no adapter OCI e setamos isso no config.ini da seguinte forma: 
resources.db.params.host            = "ftidb1d"   
resources.db.params.username   = "*****"
resources.db.params.password    = "*****"
resources.db.port                        = 1521
          resources.db.params.charset       = "UTF8"

A utilização desse parâmetro faz com que os dados retornem no charset informado, mas há estouro de buffer qnd o PDO faz a consulta.

Bug detectado: https://bugs.php.net/bug.php?id=54379

Preciso achar uma solução, já virei o google de cabeça pra baixo.




Date: Thu, 22 Sep 2011 14:39:14 -0300
Subject: Re: [phpba] FW: Problema insolucionável?
From: con...@klaussilveira.com
To: ph...@googlegroups.com

felipe moraes

unread,
Sep 22, 2011, 7:08:28 PM9/22/11
to ph...@googlegroups.com
Imagino que não tenha haver com o oracle em si, deve ser problema de charset.

Aplicação UTF8

Banco ISO  e Conexão com o banco AL32UTF8. Você está convertendo de UTF8 para ISO (utf8_decode)?

AL32UTF8 is a varying width characterset, which means that the code for a character can be 1, 2, 3, or 4 bytes long. This is a big difference with charactersets like WE8ISO8859P1 or WE8MSWIN1252.

Ou seja, 1 caracter por ocupar até 4 bytes (4 caracteres).

O erro diz que o valor ficou truncado, geralmente por que a string é maior que o campo.

Vê aí se troca o charset do campo, ou o tamanho dele.

hugo emanoel borges

unread,
Sep 22, 2011, 9:35:12 PM9/22/11
to ph...@googlegroups.com
O problema é com charset sim. As consultas efetuadas sem definir o charset de conexão do PDO, ou seja, utilizando o padrão do banco WE8ISO8859P1, para serem exibidas (os dados) necessitam que sejam convertidas com a função utf8_encode(), pois a aplicação está com o Content-type definido como UTF8. Quando definimos no arquivo de configuração que a conexão do PDO utilize o charset UTF8, há um estouro de buffer na hora que o PDO executa um select que contenha um atributo com acentos, cedilhas e caracteres especiais. Esses caracteres utilizam "2 espaços" no buffer, ou seja, num caso hipotético, um campo char(4) que contenha o dado "ÇÇÇÇ" vai dar um estouro e informa que o tamanho necessário é o dobro. Entendeu??

Não consigo de forma alguma uma solução para esse problema. Já revirei o google hoje de tarde e n existe solução pra isso.

Help!!!!!


Att,


Hugo Borges
Analista de Sistemas



Date: Thu, 22 Sep 2011 20:08:28 -0300

Subject: Re: [phpba] FW: Problema insolucionável?

Márcio Albuquerque

unread,
Sep 23, 2011, 7:16:47 AM9/23/11
to ph...@googlegroups.com
Cara, tentou a ideia do Klaus? Trabalhar com Multibyte String?

Atenciosamente,
Márcio Albuquerque
-------------------------------------------------------------------
Serviço Federal de Processamento de Dados - SERPRO
Grupo LinguÁgil - Misturando Linguagens e Agilidade
Salvador - BA
(71) 2102 7962 / (71) 8880 4994

-------------------------------------------------------------------

Márcio Albuquerque

unread,
Sep 23, 2011, 7:19:07 AM9/23/11
to ph...@googlegroups.com
Outra coisa, não tem como mudar o charset do BD não?


Atenciosamente,
Márcio Albuquerque
-------------------------------------------------------------------
Serviço Federal de Processamento de Dados - SERPRO
Grupo LinguÁgil - Misturando Linguagens e Agilidade
Salvador - BA
(71) 2102 7962 / (71) 8880 4994

-------------------------------------------------------------------



hugo emanoel borges

unread,
Sep 23, 2011, 8:22:24 AM9/23/11
to ph...@googlegroups.com
Mudar o charset do banco é inviável, pq tem centenas de aplicações aqui no Oracle. A extensão mb_string já está ativa e, pelo que imagino, não tem como interferir no PDO, já que o core dele é fechado e utilizado pelo Zend.

Se não estou enganado é mais ou menos assim... Chamamos por exemplo a função fetchAll() do  Zend_Db_Table, que chama o Zend_Db_Adapter, que chama o adapter cadastrado no factory, no meu caso é o Zend_Db_Adapter_Pdo_Oci pq é o Oracle. A função executa o fetchAll utilizando o PDOStatement e o erro retorna de lá do core do PDOStatement.




Date: Fri, 23 Sep 2011 08:19:07 -0300

Subject: Re: [phpba] FW: Problema insolucionável?

hugo emanoel borges

unread,
Sep 23, 2011, 8:32:01 AM9/23/11
to ph...@googlegroups.com
( ! ) Warning: PDOStatement::fetchAll() [pdostatement.fetchall]: column 1 data was too large for buffer and was truncated to fit it in C:\wamp\www\library\Zend\Db\Statement\Pdo.php on line 290
Call Stack
#TimeMemoryFunctionLocation
10.0011392040{main}( )..\index.php:0
20.26446834520Zend_Application->run( )..\index.php:54
30.26456834520Zend_Application_Bootstrap_Bootstrap->run( )..\Application.php:366
40.26466834576Zend_Controller_Front->dispatch( )..\Bootstrap.php:97
50.28277514288Zend_Controller_Dispatcher_Standard->dispatch( )..\Front.php:954
60.42258779960Zend_Controller_Action->dispatch( )..\Standard.php:295
70.42268784552ConsumidorController->addAction( )..\Action.php:513
80.43499762696ConsumidorForm->__construct( )..\ConsumidorController.php:31
90.43519764496App_Form_Abstract->__construct( )..\ConsumidorForm.php:24
100.43599768160ZendX_JQuery_Form->__construct( )..\Abstract.php:14
110.43619769720Zend_Form->__construct( )..\Form.php:47
120.43619769720ConsumidorForm->init( )..\Form.php:240
132.514811548256Mapper_Localidade->fetchAll( )..\ConsumidorForm.php:86
142.514811548256App_Db_Mapper_Abstract->fetchAll( )..\Localidade.php:66
152.514811548256Zend_Db_Table_Abstract->fetchAll( )..\Abstract.php:98
163.224311558136App_Db_Abstract->_fetch( )..\Abstract.php:1321
173.224311558136Zend_Db_Table_Abstract->_fetch( )..\Abstract.php:108
183.264111563704Zend_Db_Statement_Pdo_Oci->fetchAll( )..\Abstract.php:1506
193.264111563736Zend_Db_Statement_Pdo->fetchAll( )..\Oci.php:57
203.264111563768PDOStatement->fetchAll( )..\Pdo.php:290
Variables in local scope (#19)
$col =
null
$e =
Undefined
$style =
int 2






From: hemb...@hotmail.com
To: ph...@googlegroups.com
Subject: RE: [phpba] FW: Problema insolucionável?
Date: Fri, 23 Sep 2011 09:22:24 -0300

Márcio Albuquerque

unread,
Sep 23, 2011, 8:46:26 AM9/23/11
to ph...@googlegroups.com
Ok, extensão tá ligada, mas tá usando ela? Ou o Zend já usa por padrão se estiver ligada?

Tem métodos de codificação e decodificação diferentes; transformação de tipos (até para japonês).


Atenciosamente,
Márcio Albuquerque
-------------------------------------------------------------------
Serviço Federal de Processamento de Dados - SERPRO
Grupo LinguÁgil - Misturando Linguagens e Agilidade
Salvador - BA
(71) 2102 7962 / (71) 8880 4994

-------------------------------------------------------------------



felipe moraes

unread,
Sep 23, 2011, 8:50:20 AM9/23/11
to ph...@googlegroups.com
Nunca passei por esse problema, na época usava Adodb, não sei o que ele fazia para evitar isso.

o que sugeri foi mudar charset do campo problemático, e não do banco todo. Como não achei referencia sobre isso, aqui vai uma sugestão:

VARCHAR2(11 BYTE)
VARCHAR2(11 CHAR)

Veja se é possível mudar para CHAR, como o CHAR ocupará mais de 1BYTE, não terá problema.

Ocupa-se mais espaço, mas evita-se esse problema.

felipe moraes

unread,
Sep 23, 2011, 8:53:42 AM9/23/11
to ph...@googlegroups.com
Não sei que raio de língua é essa,

mas esse artigo aqui


sugere a mesma coisa:


CREATE TABLE utf8test ( 
 F1 varchar2(10), 
 F2 varchar2(10 byte), 
 F3 varchar2(10 char) <<<----
);


COLUMN_NAME DATA_LEN CHAR_LEN CHAR_USED 
F1          10       10       B 
F2          10       10       B 
F3          30       10       B <<<-----


F3 ocupa 3x o espaço declarado, mas deve resolver.

hugo emanoel borges

unread,
Sep 23, 2011, 9:13:56 AM9/23/11
to ph...@googlegroups.com
Márcio, não sei te responder. O problema é que o erro ocorre na busca dentro do próprio PDO.


20    3.2641   11563768   
PDOStatement->fetchAll( )     
..\Pdo.php:290

Ou seja, não tem como eu reescrever essa função. O POG que eu fiz foi o código abaixo... é o mais longe que eu posso ir, já que o _fetch da superclasse começa a utilizar o PDO a partir daí. Nessa classe eu mantenho a conexão com o banco no formado  de charset ISO e faço a conversão via código (né possível que não tenha uma solução pra isso).


public function _fetch(Zend_Db_Table_Select $select) {

        $return = parent::_fetch($select); //Executa o select no Zend_Db_Table_Abstract
       
        if (is_array($return)){
            foreach($return as $keyData => $data){
                foreach($data as $keyElement => $element){
                    if (is_string($element)){
                        $return[$keyData][$keyElement] = utf8_encode($element);
                    }
                }
            }
        }
        return $return;

    }


Att,


Hugo Borges
Analista de Sistemas





Date: Fri, 23 Sep 2011 09:46:26 -0300

hugo emanoel borges

unread,
Sep 23, 2011, 9:17:21 AM9/23/11
to ph...@googlegroups.com
Felipe, tudo bem?

A estrutura do banco eu não posso alterar pq é uma materialização que fizeram do DB2 lá no Oracle e outras aplicações utilizam, inclusive o problema também acontece tanto em tabela quanto em visões e sinonimos.

O problema não está também em um único campo e sim em qualquer outro que possua acento ou caracteres especiais pq o banco inteiro é ISO8859.



Att,


Hugo Borges
Analista de Sistemas


Date: Fri, 23 Sep 2011 09:53:42 -0300
Reply all
Reply to author
Forward
0 new messages