You are here

sqlsrv.install in Drupal driver for SQL Server and SQL Azure 8

Installation file for sqlsrv module.

File

sqlsrv.install
View source
<?php

/**
 * @file
 * Installation file for sqlsrv module.
 */
use Drupal\Core\Database\Database;
use Drupal\Driver\Database\sqlsrv\Connection;
use Drupal\Driver\Database\sqlsrv\Utils;
use Drupal\sqlsrv\Indexes\IndexManager;

/**
 * Implements hook_uninstall().
 *
 * Remove cache directory if module is uninstalled.
 */
function sqlsrv_uninstall() {
}

/**
 * Implements hook_requirements().
 *
 * @status: Needs global revision.
 */
function sqlsrv_requirements($phase) {
  $requirements = array();
  if ($phase == 'runtime') {

    /** @var Connection $connection */
    $connection = Database::getConnection();

    // Nothing to do if we are not running on MSSQL.
    if ($connection
      ->driver() !== 'sqlsrv') {
      return array();
    }
    $options = $connection
      ->getConnectionOptions();
    $schema = $connection
      ->schema();
    $collation = $schema
      ->getCollation();
    $version = $schema
      ->EngineVersion();
    $extensiondata = Utils::ExtensionData('pdo_sqlsrv');

    // Report database engine version
    $uinfo = $schema
      ->UserOptions();
    $uinfo_parts = array_map(function ($a, $b) {
      $a = strtoupper($a);
      $b = strtoupper($b);
      return "{$a}={$b}";
    }, array_keys($uinfo), $uinfo);
    $requirements['sqlsrv_edition'] = array(
      'title' => t('MSSQL Server'),
      'severity' => REQUIREMENT_INFO,
      'description' => implode(' | ', $uinfo_parts),
      'value' => t('@version @level @ @edition | @name', array(
        '@version' => $version['VERSION'],
        '@level' => $version['LEVEL'],
        '@edition' => $version['EDITION'],
        '@name' => $options['database'],
      )),
    );

    // Report database name and size.
    $size = $schema
      ->getSizeInfo();
    $size_db = format_size($size->RowSizeMB * 1024 * 1024);
    $requirements['sqlsrv_database'] = array(
      'title' => t('MSSQL Server Database'),
      'severity' => REQUIREMENT_OK,
      'value' => "{$options['database']} ({$size_db})",
    );

    // Make sure enough size is set for buffered queries
    $buffer_size = $extensiondata['getINIEntries']['pdo_sqlsrv.client_buffer_max_kb_size'];
    $buffer_size_min = 12240 * 2;
    $buffer_size_ok = $buffer_size >= $buffer_size_min;
    $requirements['sqlsrv_client_buffer_size'] = array(
      'title' => t('MSSQL Server client buffer size'),
      'severity' => $buffer_size_ok ? REQUIREMENT_OK : REQUIREMENT_WARNING,
      'value' => "{$buffer_size} Kb",
      'description' => "pdo_sqlsrv.client_buffer_max_kb_size setting must be of at least {$buffer_size_min}Kb. Currently {$buffer_size}Kb.",
    );

    // Is this a windows server?
    // Probably yes, because this is the MS SQL Server driver!
    $is_windows = Utils::WindowsOS();
    if ($is_windows) {
      $wincache_module = \Drupal::moduleHandler()
        ->moduleExists('wincachedrupal');
      $requirements['sqlsrv_wincache_extension'] = array(
        'title' => t('MSSQL Server Wincache module'),
        'value' => $wincache_module ? phpversion('wincache') : t('Not available'),
        'severity' => $wincache_module ? REQUIREMENT_OK : REQUIREMENT_ERROR,
        'description' => $wincache_module ? NULL : t('Enabling wincache integration can greatly improve system performance. See <a href="https://www.drupal.org/project/wincachedrupal/">Wincache Drupal</a> for more details.'),
      );
      $fastcache_enabled = (new \Drupal\Driver\Database\sqlsrv\FastCache(''))
        ->Enabled() && $wincache_module;
      $requirements['sqlsrv_wincache_integration'] = array(
        'title' => t('MSSQL Server Wincache integration'),
        'value' => $fastcache_enabled ? t('Available') : t('Not available'),
        'severity' => $fastcache_enabled ? REQUIREMENT_OK : REQUIREMENT_ERROR,
        'description' => $fastcache_enabled ? NULL : t('MSSQL Server / Wincache integration is not available.'),
      );
    }

    // Report encoding for database.
    $collation = $schema
      ->getCollation();
    $case_insensitive = stripos($collation, '_CI') !== FALSE;
    $requirements['sqlsrv_encoding_database'] = array(
      'title' => t('MSSQL Server Database encoding'),
      'severity' => $case_insensitive ? REQUIREMENT_OK : REQUIREMENT_ERROR,
      'description' => $case_insensitive ? NULL : t('Drupal needs a default case insensitive collation database to run on.'),
      'value' => t('@collation', array(
        '@collation' => $collation,
      )),
    );

    // Report PDO version, and require at lest 3.2 version.
    $version_ok = version_compare($extensiondata['getVersion'], '3.2') >= 0;
    $requirements['sqlsrv_pdo'] = array(
      'title' => t('MSSQL Server PDO extension'),
      'severity' => $version_ok ? REQUIREMENT_OK : REQUIREMENT_ERROR,
      'value' => t('@level', array(
        '@level' => $extensiondata['getVersion'],
      )),
      'description' => t('Use at least the 3.2.0.0 version of the MSSQL PDO driver.'),
    );

    // TODO: Report install function availability (SUBSTRING, CONCAT, IF, MD5, etc...)
    $schema = $connection
      ->schema();
    $functions = $schema
      ->DrupalSpecificFunctions();
    $briefing = array();
    $error = FALSE;
    foreach ($functions as $function) {
      $exists = $schema
        ->functionExists($function);
      $error = $exists === FALSE ? TRUE : $error;
      $briefing[] = $function . ':' . ($exists === TRUE ? 'YES' : 'NO');
    }
    $exists = $schema
      ->CLREnabled();
    $error = $exists === FALSE ? TRUE : $error;
    $briefing[] = 'CLREnabled' . ':' . ($exists === TRUE ? 'YES' : 'NO');
    $requirements['sqlsrv_custom_functions'] = array(
      'title' => t('MSSQL Server Custom Functions'),
      'description' => $error === TRUE ? t('Some custom functions are not available. Make sure you deploy them.') : t('All custom functions available.'),
      'severity' => $error === TRUE ? REQUIREMENT_ERROR : REQUIREMENT_OK,
      'value' => implode(' | ', $briefing),
    );

    // TODO:// Move this to a better place!
    $manager = new IndexManager($connection);
    $manager
      ->DeployNew();

    // Redeploy functions
    Utils::DeployCustomFunctions($connection, TRUE);

    // Make sure that the module's driver code is the same one as the effectively
    // deployed driver code....
    // TODO:// Nicer than just showing the error,
    // would be to offer the option to autodploy the driver...
    if ($connection->driver_settings
      ->GetMonitorDriverStatus()) {
      $deployed_ok = sqlsrv_verify_driver();
      $requirements['sqlsrv_deployed_files'] = array(
        'title' => t('MSSQL Server Deployed Driver'),
        'description' => t('Deployed driver match.'),
        'severity' => $deployed_ok === TRUE ? REQUIREMENT_OK : REQUIREMENT_ERROR,
        'description' => $deployed_ok === TRUE ? t('Deployed driver matches module version.') : t('The deployed driver files do not match the module driver.'),
      );
    }
  }
  return $requirements;
}

/**
 * Verify that the deployed driver is the same one as the module
 * version.
 * 
 * @return bool
 */
function sqlsrv_verify_driver() {

  // Location of the effective driver.
  $class = Connection::class;
  $reflector = new ReflectionClass($class);
  $driver_dir = dirname($reflector
    ->getFileName());

  // Location for the module's driver.
  $module_dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, array(
    'drivers',
    'lib',
    'drupal',
    'driver',
    'database',
    'sqlsrv',
  ));
  return sqlsrv_directory_checksum($driver_dir) === sqlsrv_directory_checksum($module_dir);
}

/**
 * Calculate a unique identifier for a directory and it's contents
 * based on file sizes and names.
 * 
 * TODO:// This thing will not notice files being moved around in directories
 * as long as they keep same name and size.
 * 
 * @param string $directory 
 * @return string
 */
function sqlsrv_directory_checksum($directory) {
  $files = file_scan_directory($directory, '/\\.*/i');
  $checksum = 0;
  $names = '';
  foreach ($files as $file) {
    $checksum += filesize($file->uri);
    $names .= $file->name;
  }
  return $checksum . '-' . md5($names);
}

Functions

Namesort descending Description
sqlsrv_directory_checksum Calculate a unique identifier for a directory and it's contents based on file sizes and names.
sqlsrv_requirements Implements hook_requirements().
sqlsrv_uninstall Implements hook_uninstall().
sqlsrv_verify_driver Verify that the deployed driver is the same one as the module version.