PHP: Instalar PDO_SQLSRV en Linux

Buscando en los modulos de Ubuntu/Debian no aparece la extensión para PHP de PDO_SQLSRV, solamente tenemos:

  • php7.0-pdo-firebird
  • php7.0-pdo-pgsql
  • php7.0-pdo-sqlite
  • php7.0-pdo-odbc
  • php7.0-pdo-mysql
  • php7.0-pdo-dblib

Y nada que diga php7.0-pdo-sqlsrv, pero la solución es compilar la extensión manualmente, gracias a PEAR, como root ejecutamos:

apt-get install unixodbc-dev php7.0-dev php-pear

pecl install pdo_sqlsrv-4.0.5

echo -e “; priority=20\nextension=pdo_sqlsrv.so” > /etc/php/7.0/mods-available/pdo_sqlsrv.ini

phpenmod -v 7.0 pdo_sqlsrv

/etc/init.d/php7.0-fpm restart

Y listo, deberíamos de tener en nuestro phpinfo() algo así:

Si utilizamos windows, descargamos la extensión desde aquí: Microsoft Drivers for PHP for SQL Server y este link para instalar el driver Microsoft ODBC Driver 13 for SQL Server

Y listo, ya nos podemos conectar al servidor SQL Server desde PHP.

SQL Server: No regresa el texto completo en las celdas con valores tipo texto, modificar php.ini

Siguiendo con el tema del truncado de caracteres en SQL desde nuestra aplicación de PHP del post anterior, resulta que la solución también se puede hacer con el comando SQL.

SET TEXTSIZE NUMERO_CARACTERES_A_OBTENER

Pero igual si queremos algo más permanente, solo es cosa de modificar nuestro archivo PHP.ini, las lineas donde tengamos:

; Valid range 0 – 2147483647. Default = 4096.
;mssql.textlimit = 4096

; Valid range 0 – 2147483647. Default = 4096.
;mssql.textsize = 4096

Por lo general están comentadas estas lineas, solo es cosa de descomentarlas y poner el valor que deseemos, reiniciamos apache y listo 🙂

SQL Server: No regresa el texto completo en las celdas con valores tipo texto

Si tienes un campo de tipo texto, ya sea cualquiera de los siguientes tipos de datos:

  • varchar(max)
  • nvarchar(max)
  • varbinary(max)
  • text
  • ntext
  • image

Y cuando realizas tu select, no te regresa la información completa, entonces lo que debes de hacer es incrementar el limite de la variable textsize.

Para saber cual es el límite actual solo ejecuta el siguiente comando:

SELECT @@TEXTSIZE

Casi por default te dará un valor de 2147483647 (caracteres)

Y entonces la solución antes de ejecutar tu consulta SELECT, debes de iniciar con la siguiente consulta SQL.

SET TEXTSIZE NUMERO_CARACTERES_A_OBTENER

Digamos que deseas obtener unos 200 caracteres, entonces ejecutas SET TEXTSIZE 200 ,seguido de tu sentencia SQL del SELECT.

Codeigniter: Modificar LIMIT para el driver MSSQL

Después de encontrar la solución para que funcione el LIMIT de MySQL en Microsoft SQL Server ahora sigue el turno de modificar el código de Codeigniter para así tener algo transparente para nuestras consultas SQL.

Lo primero que se debe de hacer es modificar la librería de carga del Codeigniter, ( $this->load-> )
Vamos a trabajar en la carpeta: /system/application/libraries/ y creamos un archivo llamado: MY_Loader.php con el siguiente código:

< ?php class MY_Loader extends CI_Loader{ / * Constructor, calls parent constructor. */ function MY_Loader() { parent::CI_Loader(); } / * Database Loader * * @access public * @param string the DB credentials * @param bool whether to return the DB object * @param bool whether to enable active record (this allows us to override the config setting) * @return object */ function database($params = '', $return = FALSE, $active_record = FALSE) { // Do we even need to load the database class? if (class_exists('CI_DB') AND $return == FALSE AND $active_record == FALSE) { return FALSE; } require_once(BASEPATH.'database/DB'.EXT); // Load the DB class $db =& DB($params, $active_record); $my_driver = config_item('subclass_prefix').'DB_'.$db->dbdriver.’_driver’;
$my_driver_file = APPPATH.’libraries/’.$my_driver.EXT;

if (file_exists($my_driver_file))
{
require_once($my_driver_file);
$db =& new $my_driver(get_object_vars($db));
}

if ($return === TRUE)
{
return $db;
}
// Grab the super object
$CI =& get_instance();

// Initialize the db variable. Needed to prevent
// reference errors with some configurations
$CI->db = ”;
$CI->db = $db;
// Assign the DB object to any existing models
$this->_ci_assign_to_models();
}

}

La idea de este archivo es extender la funcionalidad de carga de los drivers para la base de datos, despues en la misma carpeta de libraries creamos un archivo llamado: MY_DB_mssql_driver.php ya que estamos usando el driver mssql para nuestra conexión SQL Server

< ?php class MY_DB_mssql_driver extends CI_DB_mssql_driver { function __construct($params){ parent::__construct($params); log_message('debug', 'Extended DB driver class instantiated!'); } function _limit($sql, $limit, $offset){ if($offset == 0){ return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); }else{ $OrderBy = "ORDER BY "; if (count($this->ar_orderby) > 0){
$OrderBy .= implode(‘, ‘, $this->ar_orderby);

if ($this->ar_order !== FALSE)
{
$OrderBy .= ($this->ar_order == ‘desc’) ? ‘ DESC’ : ‘ ASC’;
}
}else{
$OrderBy .= “(SELECT 1)”;
}

$sql = preg_replace(‘/(\\’. $OrderBy .’\n?)/i’,”, $sql);
$sql = preg_replace(‘/(^\SELECT (DISTINCT)?)/i’,’\\1 ROW_NUMBER() OVER (‘.$OrderBy.’) AS rownum, ‘, $sql);
return “SELECT * \nFROM (\n” . $sql . “) AS A \nWHERE A.rownum BETWEEN (” .($offset + 1) . “) AND (“.($offset + $limit).”)”;
}
}

Y listo! con esto nuestra consulta LIMIT será transparente y se usará como siempre: $this->db->limit(2,10);

Aca les dejo las fuentes de esta información:

No existe offset (antes decia: LIMIT) en MS SQL Server

Así como suena el titulo, en Microsoft SQL Server no existe la función limit , para implementarla tienes que usar algunos trucos con subconsultas., algo tan sencillo en MySQL como: SELECT * FROM miTabla LIMIT 2,10 en SQL Server se vuelve una calamidad.

Buscando en Internet, encontré en Foros del Web una explicación de como hacer funcionar, se tiene que poner una subconsulta SQL con algo que diga: ROW_NUMBER() OVER (ORDER BY campo) as NumRows y despues se hace un WHERE con su respectivo Between para poner el limite: WHERE NumRows BETWEEN 2 AND 10

Aca un ejemplo más elaborado:

SELECT *
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY mi_Campo1) AS NumRows, *
FROM mi_Tabla
) as AS_NumRows
WHERE AS_NumRows.NumRows BETWEEN 10 AND 20

Si se requiere algún WHERE en nuestra consulta SQL se debe de meter en la subquery, en caso que no tengamos ningun campo a ordenar se cambia lo que tiene ROW_NUMBER, ORDER BY por la siguiente información:

ROW_NUMBER() OVER (ORDER BY (SELECT 1))

Y listo!.., no he probado el rendimiento pero pues aquí una solución extra.

SqlServer: Error al guardar los cambios de una tabla previamente creada

Desde que he usado Microsoft SQLServer siempre me ha dado el problema de cuando tengo una tabla ya creada y despues quiero modificar algun campo ya existente me dice que no se puede guardar:

Saving changes is not permitted. The changes you have made require the following tables to be dropped an re-created. You have either made changes to a table that can’t be re-created or enabled option Prevent saving changes that require the table to be re-created

Y bueno, pues lo que hacia antes era volver a crear otra tabla, ponerle un nombre temporal, eliminar la anterior y luego cambiar el nombre de la tabla, como ven nada eficiente., y pues la otra solución como lo indica el mensaje de error es deshabilitar la opción de prevenir cambios al guardar.

Entramos al menú: Tools > Options > Designers y quitamos la palomita del texto: Prevent saving changes that require table re-creation.

Y listo!! ya podemos modificar campos.., claro que hay que tener cuidado con los tipos de datos porque si tenemos información puede meter inconsistencias.

SQLServer y PHP: Error con Heterogeneous queries require the ANSI_NULLS and ANSI_WARNINGS

Al conectarme a una vista de MS SQLServer desde PHP, me aparecio el siguiente error en el log del codeigniter:

message: Heterogeneous queries require the ANSI_NULLS and ANSI_WARNINGS options to be set for the connection. This ensures consistent query semantics. Enable these options and then reissue your query. (severity 16)

Y pues la consulta SQL no se ejecuta., la solución es ejecutar antes las siguientes consultas SQL:

SET ANSI_WARNINGS ON
SET ANSI_NULLS ON

Y despues ya ejecutar su consulta normal, digamos que en codeigniter tendriamos algo asi:

$this->db->query('SET ANSI_WARNINGS ON');
$this->db->query('SET ANSI_NULLS ON');

Y listo! asunto arreglado 🙂

Aca una explicación en ingles desde la página de Microsoft

Error al conectar MS SQLServer mediante Localhost y 127.0.0.1

Intentaba conectarme al servidor Microsoft SQL Server mediante el nombre localhost y me marcaba que no tenia acceso, luego intente con la IP 127.0.0.1 y nada, el mismo error, pero si ponia el nombre completo de la maquina + el nombre (LAP/SQLEXPRESS) del servidor SQLServer ahí si podia ingresar!,

TITLE: Connect to Server
——————————
Cannot connect to localhost.
——————————
ADDITIONAL INFORMATION:
Error relacionado con la red o específico de la instancia mientras se establecía una conexión con el servidor SQL Server. No se encontró el servidor o éste no estaba accesible. Compruebe que el nombre de la instancia es correcto y que SQL Server está configurado para admitir conexiones remotas. (provider: Proveedor de canalizaciones con nombre, error: 40 – No se pudo abrir una conexión con SQL Server) (Microsoft SQL Server, Error: 2)

For help, click: http://go.microsoft.com/fwlink?ProdName=Microsoft+SQL+Server&EvtSrc=MSSQLServer&EvtID=2&LinkId=20476

Investigando sobre el error, me encuentro que se tiene que activar la opción TCP/IP y agregar el puerto correspondiente al SQLServer, para hacer estos cambios ingresar en:

Inicio > Programas > Microsoft SQL Server 2008 R2 > Configuration Tools > (Aquí depende de tu versión del SQL Server)
Sql Server Configuration Manager > SQL Server Network Configuration > Protocols for SQLEXPRESS > TCP/IP
Botón derecho, propiedades y cambiar:
Protocols > Enabled = true
IP Address > IP ALL > TCP Dynamic Ports = 1433

Aceptar y luego reiniciar el servicio del SQLServer ( SQL Server Services > SQL Server (EXPRESS) > Botón derecho, reiniciar)

Y listo!., ya podemos entrar agregando la IP o el nombre localhost.