¿Te ha pasado que una consulta en SAP HANA devuelve cientos de registros correctamente, pero al consumirla desde PHP mediante ODBC solamente recibes uno?
Eso fue exactamente lo que ocurrió en este caso: una consulta en SAP HANA tenía 902 registros, pero desde PHP, al incluir la descripción del artículo OITM."ItemName", odbc_fetch_array() solamente recuperaba 1 registro.
Después de varias pruebas se pudo determinar que no era un problema de memoria, SQL, JOIN, PHP ni del while.
La solución fue configurar correctamente el controlador SAP HANA ODBC para manejar los caracteres mediante UTF-8:
CHAR_AS_UTF8=true
manteniendo:
EnableArrayFetch=1
La configuración se aplicó tanto en Linux Mint como en Windows 10.
🚨 El problema
La consulta original era similar a:
SELECT
a."ItemCode",
b."ItemName",
a."Price",
a."PriceList",
c."ListName"
FROM ITM1 a
INNER JOIN OITM b
ON a."ItemCode" = b."ItemCode"
INNER JOIN OPLN c
ON a."PriceList" = c."ListNum"
WHERE a."PriceList" = 1
AND IFNULL(a."Price", 0) > 0;
En SAP HANA la consulta contenía 902 artículos con precio.
Sin embargo, PHP solamente recibía:
1 registro
y no aparecía ningún error ODBC.
El código PHP era completamente normal:
while ($row = odbc_fetch_array($stmt)) {
$data[] = [
'ItemCode' => $row['ItemCode'],
'ItemName' => $row['ItemName'],
'Price' => (float) $row['Price'],
'PriceList' => (int) $row['PriceList'],
'ListName' => $row['ListName'],
];
}
🔍 Primero: comprobar si realmente existen los registros
Antes de culpar a PHP u ODBC, se comprobó directamente en HANA:
SELECT COUNT(*) AS "Total"
FROM ITM1
WHERE "PriceList" = 1
AND IFNULL("Price", 0) > 0;
Resultado:
902
Por lo tanto, los datos sí existían.
🧪 Diagnóstico paso a paso
Para encontrar el problema se fue simplificando la consulta.
1️⃣ Solamente ITM1
SELECT
"ItemCode",
"Price",
"PriceList"
FROM ITM1
WHERE "PriceList" = 1
AND IFNULL("Price", 0) > 0;
Desde PHP:
TOTAL: 902
✅ ITM1 funcionaba correctamente.
2️⃣ Agregar el JOIN con OITM
Se añadió:
INNER JOIN OITM b
ON a."ItemCode" = b."ItemCode"
pero solamente se recuperó el código:
SELECT
a."ItemCode",
b."ItemCode"
FROM ITM1 a
INNER JOIN OITM b
ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1
AND IFNULL(a."Price", 0) > 0;
Resultado:
TOTAL: 902
✅ El JOIN con OITM también funcionaba.
⚠️ 3️⃣ Agregar ItemName
El problema apareció cuando se añadió:
b."ItemName"
La consulta:
SELECT
a."ItemCode",
b."ItemName"
FROM ITM1 a
INNER JOIN OITM b
ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1
AND IFNULL(a."Price", 0) > 0;
Desde PHP solamente devolvía:
TOTAL: 1
🎯 Aquí quedó localizado el problema.
No era el JOIN.
No era ITM1.
No era OPLN.
No era memoria.
El comportamiento aparecía específicamente al recuperar el contenido de:
OITM."ItemName"
🧠 Una pista importante: los caracteres especiales
Durante las pruebas también apareció algo muy revelador.
En SAP HANA el texto era:
REV 14±2
pero PHP recibía:
REV 14±2
Eso indicaba claramente un problema de codificación de caracteres entre:
SAP HANA
↓
HDBODBC
↓
PHP
↓
JSON
↓
DataTables
Además, el problema no generaba un error ODBC tradicional.
Por eso era especialmente difícil de localizar.
🐧 Solución en Linux Mint
Primero se comprobó la configuración de unixODBC:
odbcinst -j
La salida mostraba:
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
USER DATA SOURCES..: /home/usuario/.odbc.ini
El DSN utilizado estaba en:
/etc/odbc.ini
La configuración original era:
[mi_dsn_hana]
Driver=SAP HANA
ServerNode=SERVIDOR_HANA:30015
Se añadió:
CHAR_AS_UTF8=true
Quedando:
[mi_dsn_hana]
Driver=SAP HANA
ServerNode=SERVIDOR_HANA:30015
CHAR_AS_UTF8=true
El driver utilizado estaba definido en:
/etc/odbcinst.ini
con:
[HANA_ODBC]
Description=SAP HANA ODBC Driver
Driver=/ruta/al/cliente-hana/libodbcHDB.so
🔎 Comandos útiles para localizar ODBC en Linux
Para saber dónde están los archivos:
odbcinst -j
Para ver el DSN:
cat /etc/odbc.ini
Para ver los drivers:
cat /etc/odbcinst.ini
Para buscar configuraciones relacionadas con HANA:
grep -RniE "HDB|HANA|CHAR_AS_UTF8|char_as_utf8|ServerNode|Driver" \
/etc/odbc.ini \
/etc/odbcinst.ini \
~/.odbc.ini 2>/dev/null
Para listar los DSN:
odbcinst -q -s
🪟 Solución en Windows 10
En Windows se comprobó primero la arquitectura de PHP:
php -i | findstr /I "Architecture"
Resultado:
Architecture => x64
Por lo tanto se utilizó el administrador ODBC de 64 bits:
C:\Windows\System32\odbcad32.exe
El DSN utilizado era:
mi_dsn_hana
y estaba registrado en:
HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana
Al consultar el registro:
reg query "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /s
se encontró, entre otros valores:
Driver C:\Program Files\SAP\hdbclient\libodbcHDB.dll
Host SERVIDOR_HANA
PortNumber 30015
EnableArrayFetch 1
ArrayFetchSize 5000
💾 Antes de modificar el registro: hacer respaldo
Siempre es recomendable guardar una copia del DSN.
reg export "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" "%USERPROFILE%\Desktop\mi_dsn_hana-backup.reg"
Windows responderá:
La operación se completó correctamente.
Así se dispone de un archivo de respaldo en el escritorio.
⚙️ Agregar CHAR_AS_UTF8 en Windows
Se agregó directamente al registro:
reg add "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8 /t REG_SZ /d true /f
Para comprobarlo:
reg query "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8
El resultado esperado es:
CHAR_AS_UTF8 REG_SZ true
✅ Configuración aplicada correctamente.
🔄 Reiniciar Apache
Después de modificar el DSN, es importante reiniciar Apache/XAMPP para que PHP cree una nueva conexión ODBC.
Desde XAMPP:
Stop Apache
Start Apache
O, si Apache está instalado como servicio:
net stop Apache2.4
net start Apache2.4
El nombre del servicio puede variar según la instalación.
⚙️ ¿Qué pasó con EnableArrayFetch?
El DSN de Windows ya tenía:
EnableArrayFetch=1
y:
ArrayFetchSize=5000
Durante las pruebas se decidió mantenerlo activado.
La configuración final quedó:
CHAR_AS_UTF8=true
EnableArrayFetch=1
Esto mismo se mantuvo tanto en Linux como en Windows.
No fue necesario desactivar EnableArrayFetch.
💻 La función PHP no necesitó cambios especiales
Una vez solucionada la configuración del ODBC, la consulta PHP puede seguir siendo una consulta normal:
static public function ctrMostrarListaPrecio($conn, int $id)
{
$sql = '
SELECT
a."ItemCode",
b."ItemName",
a."Price",
a."PriceList",
c."ListName"
FROM ITM1 a
INNER JOIN OITM b
ON a."ItemCode" = b."ItemCode"
INNER JOIN OPLN c
ON a."PriceList" = c."ListNum"
WHERE a."PriceList" = ?
AND IFNULL(a."Price", 0) > 0
';
$stmt = odbc_prepare($conn, $sql);
if (!$stmt) {
throw new Exception(
'Error ODBC prepare: ' . odbc_errormsg($conn)
);
}
if (!odbc_execute($stmt, [$id])) {
throw new Exception(
'Error ODBC execute: ' . odbc_errormsg($conn)
);
}
$data = [];
while ($row = odbc_fetch_array($stmt)) {
$data[] = [
'ItemCode' => $row['ItemCode'],
'ItemName' => $row['ItemName'],
'Price' => (float) $row['Price'],
'PriceList' => (int) $row['PriceList'],
'ListName' => $row['ListName'],
];
}
return $data;
}
La solución estuvo en la configuración del HDBODBC, no en cambiar la consulta.
🧪 Otra prueba importante: comprobar si era memoria
También se revisó la memoria de PHP:
echo memory_get_usage(true);
Durante las pruebas se obtuvo aproximadamente:
2097152 bytes
Y el pico:
2097152 bytes
No hubo incremento importante al procesar los registros.
Por lo tanto:
❌ No era falta de memoria.
❌ No era que 902 registros fueran demasiados.
❌ No era el while.
❌ No era odbc_prepare().
❌ No era odbc_execute().
❌ No era el JOIN.
✅ El comportamiento estaba relacionado con el tratamiento de caracteres por HDBODBC.
🛠️ Diagnóstico recomendado para futuros problemas
Cuando PHP y SAP HANA devuelvan menos registros de los esperados, no hay que asumir inmediatamente que el problema está en SQL.
Una buena estrategia es ir agregando las columnas progresivamente.
Primero:
SELECT
"ItemCode"
FROM ITM1
WHERE "PriceList" = 1;
Después:
SELECT
a."ItemCode",
b."ItemCode"
FROM ITM1 a
INNER JOIN OITM b
ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1;
Después:
SELECT
a."ItemCode",
b."ItemName"
FROM ITM1 a
INNER JOIN OITM b
ON a."ItemCode" = b."ItemCode"
WHERE a."PriceList" = 1;
De esta forma puedes identificar exactamente qué columna provoca el comportamiento.
En este caso:
ITM1 → 902
ITM1 + OITM.ItemCode → 902
ITM1 + OITM.ItemName → 1
Ese pequeño experimento permitió descubrir rápidamente que había que investigar el tratamiento del campo de texto.
📌 Configuración final
Después de todas las pruebas, la configuración que quedó funcionando fue:
CHAR_AS_UTF8=true
EnableArrayFetch=1
Linux Mint
Archivo:
/etc/odbc.ini
Configuración:
[mi_dsn_hana]
Driver=SAP HANA
ServerNode=SERVIDOR_HANA:30015
CHAR_AS_UTF8=true
Windows 10
Registro:
HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana
Valor:
CHAR_AS_UTF8 REG_SZ true
Manteniendo:
EnableArrayFetch REG_SZ 1
✅ Conclusión
El problema parecía inicialmente un problema de PHP porque:
while ($row = odbc_fetch_array($stmt))
solamente recuperaba un registro.
Sin embargo, las pruebas demostraron que SAP HANA sí tenía 902 registros y que ODBC podía recorrerlos correctamente mientras no se solicitara directamente el contenido de ItemName.
La pista definitiva fue que los textos con caracteres especiales aparecían alterados, por ejemplo:
14±2
se recibía como:
14±2
La corrección fue configurar el controlador de SAP HANA para trabajar con UTF-8:
CHAR_AS_UTF8=true
manteniendo:
EnableArrayFetch=1
La configuración fue aplicada tanto en Linux Mint como en Windows 10.
💡 Moraleja: cuando PHP + ODBC + SAP HANA devuelve menos filas de las esperadas, especialmente al trabajar con campos NVARCHAR o textos con caracteres especiales, conviene revisar primero la configuración del HDBODBC antes de modificar la consulta o asumir que existe un problema de memoria.
🚀 Resumen rápido
Linux
sudo cp /etc/odbc.ini /etc/odbc.ini.bak
sudo nano /etc/odbc.ini
Agregar:
CHAR_AS_UTF8=true
Windows 10
Respaldar:
reg export "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" "%USERPROFILE%\Desktop\mi_dsn_hana-backup.reg"
Agregar:
reg add "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8 /t REG_SZ /d true /f
Comprobar:
reg query "HKLM\SOFTWARE\ODBC\ODBC.INI\mi_dsn_hana" /v CHAR_AS_UTF8
Resultado esperado:
CHAR_AS_UTF8 REG_SZ true
Configuración final:
CHAR_AS_UTF8=true
EnableArrayFetch=1
🔧 PHP + SAP HANA + ODBC + UTF-8: un pequeño parámetro del driver puede hacer toda la diferencia.
Deja un comentario