install.inc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <?php
  2. // Microsoft SQL Server specific install functions
  3. class DatabaseTasks_sqlsrv extends DatabaseTasks {
  4. protected $pdoDriver = 'sqlsrv';
  5. public function name() {
  6. return 'Microsoft SQL Server';
  7. }
  8. public function __construct() {
  9. // Core tasks are using a table without primary key, they need to be
  10. // completely rewritten.
  11. $this->tasks = array();
  12. // Create the user-defined functions we need to be Drupal friendly.
  13. $this->tasks[] = array(
  14. 'function' => 'initializeDatabase',
  15. 'arguments' => array(),
  16. );
  17. }
  18. /**
  19. * Make SQL Server Drupal friendly.
  20. */
  21. function initializeDatabase() {
  22. $database = Database::getConnection();
  23. $database->bypassQueryPreprocess = TRUE;
  24. try {
  25. // SUBSTRING() function.
  26. $database->query(<<< EOF
  27. IF OBJECT_ID (N'SUBSTRING', N'FN') IS NOT NULL BEGIN DROP FUNCTION SUBSTRING END
  28. EOF
  29. );
  30. $database->query(<<< EOF
  31. CREATE FUNCTION [SUBSTRING](@op1 nvarchar(max), @op2 sql_variant, @op3 sql_variant) RETURNS nvarchar(max) AS
  32. BEGIN
  33. RETURN CAST(SUBSTRING(CAST(@op1 AS nvarchar(max)), CAST(@op2 AS int), CAST(@op3 AS int)) AS nvarchar(max))
  34. END
  35. EOF
  36. );
  37. // SUBSTRING_INDEX() function.
  38. $database->query(<<< EOF
  39. IF OBJECT_ID (N'SUBSTRING_INDEX', N'FN') IS NOT NULL BEGIN DROP FUNCTION SUBSTRING_INDEX END
  40. EOF
  41. );
  42. $database->query(<<< EOF
  43. CREATE FUNCTION [SUBSTRING_INDEX](@string varchar(8000), @delimiter char(1), @count int) RETURNS varchar(8000) AS
  44. BEGIN
  45. DECLARE @result varchar(8000)
  46. DECLARE @end int
  47. DECLARE @part int
  48. SET @end = 0
  49. SET @part = 0
  50. IF (@count = 0)
  51. BEGIN
  52. SET @result = ''
  53. END
  54. ELSE
  55. BEGIN
  56. IF (@count < 0)
  57. BEGIN
  58. SET @string = REVERSE(@string)
  59. END
  60. WHILE (@part < ABS(@count))
  61. BEGIN
  62. SET @end = CHARINDEX(@delimiter, @string, @end + 1)
  63. IF (@end = 0)
  64. BEGIN
  65. SET @end = LEN(@string) + 1
  66. BREAK
  67. END
  68. SET @part = @part + 1
  69. END
  70. SET @result = SUBSTRING(@string, 1, @end - 1)
  71. IF (@count < 0)
  72. BEGIN
  73. SET @result = REVERSE(@result)
  74. END
  75. END
  76. RETURN @result
  77. END
  78. EOF
  79. );
  80. // GREATEST() function.
  81. $database->query(<<< EOF
  82. IF OBJECT_ID (N'GREATEST', N'FN') IS NOT NULL BEGIN DROP FUNCTION GREATEST END
  83. EOF
  84. );
  85. $database->query(<<< EOF
  86. CREATE FUNCTION [GREATEST](@op1 real, @op2 real) RETURNS real AS
  87. BEGIN
  88. DECLARE @result real
  89. SET @result = CASE WHEN @op1 >= @op2 THEN @op1 ELSE @op2 END
  90. RETURN @result
  91. END
  92. EOF
  93. );
  94. // CONCAT() function.
  95. $database->query(<<< EOF
  96. IF OBJECT_ID (N'CONCAT', N'FN') IS NOT NULL BEGIN DROP FUNCTION CONCAT END
  97. EOF
  98. );
  99. $database->query(<<< EOF
  100. CREATE FUNCTION [CONCAT](@op1 sql_variant, @op2 sql_variant) RETURNS nvarchar(4000) AS
  101. BEGIN
  102. DECLARE @result nvarchar(4000)
  103. SET @result = CAST(@op1 AS nvarchar(4000)) + CAST(@op2 AS nvarchar(4000))
  104. RETURN @result
  105. END
  106. EOF
  107. );
  108. // IF(expr1, expr2, expr3) function.
  109. $database->query(<<< EOF
  110. IF OBJECT_ID (N'IF', N'FN') IS NOT NULL BEGIN DROP FUNCTION [IF] END
  111. EOF
  112. );
  113. $database->query(<<< EOF
  114. CREATE FUNCTION [IF](@expr1 sql_variant, @expr2 sql_variant, @expr3 sql_variant) RETURNS sql_variant AS
  115. BEGIN
  116. DECLARE @result sql_variant
  117. SET @result = CASE WHEN CAST(@expr1 AS int) != 0 THEN @expr2 ELSE @expr3 END
  118. RETURN @result
  119. END
  120. EOF
  121. );
  122. // MD5(expr1) function.
  123. $database->query(<<< EOF
  124. IF OBJECT_ID (N'MD5', N'FN') IS NOT NULL BEGIN DROP FUNCTION [MD5] END
  125. EOF
  126. );
  127. $database->query(<<< EOF
  128. CREATE FUNCTION [MD5](@value varchar(255)) RETURNS varchar(32) AS
  129. BEGIN
  130. RETURN SUBSTRING(sys.fn_sqlvarbasetostr(HASHBYTES('MD5', @value)),3,32);
  131. END
  132. EOF
  133. );
  134. // LPAD(@str, @len, @padstr) function.
  135. $database->query(<<< EOF
  136. IF OBJECT_ID (N'LPAD', N'FN') IS NOT NULL BEGIN DROP FUNCTION [LPAD] END
  137. EOF
  138. );
  139. $database->query(<<< EOF
  140. CREATE FUNCTION [dbo].[LPAD](@str nvarchar(max), @len int, @padstr nvarchar(max)) RETURNS nvarchar(4000) AS
  141. BEGIN
  142. RETURN left(@str + replicate(@padstr,@len),@len);
  143. END
  144. EOF
  145. );
  146. // CONNECTION_ID() function.
  147. $database->query(<<< EOF
  148. IF OBJECT_ID (N'CONNECTION_ID', N'FN') IS NOT NULL BEGIN DROP FUNCTION [CONNECTION_ID] END
  149. EOF
  150. );
  151. $database->query(<<< EOF
  152. CREATE FUNCTION [dbo].[CONNECTION_ID]() RETURNS smallint AS
  153. BEGIN
  154. DECLARE @var smallint
  155. SELECT @var = @@SPID
  156. RETURN @Var
  157. END
  158. EOF
  159. );
  160. $database->bypassQueryPreprocess = FALSE;
  161. }
  162. catch (Exception $e) {
  163. $this->fail(st('Drupal could not be correctly setup with the existing database. Revise any errors.'));
  164. }
  165. }
  166. // Modify the default options form to allow Windows authentication.
  167. public function getFormOptions($database) {
  168. $form = array();
  169. drupal_set_message(t('To install this version of the MS SQL Server driver make sure you have this patch in core: <a target="_blank" href="!url">!url</a>',
  170. array('!url' => 'https://www.drupal.org/node/2376239')), 'warning');
  171. include_once('reflexiondata.inc');
  172. $extensiondata = sqlsrv_REData(new ReflectionExtension('pdo_sqlsrv'));
  173. // Client buffer size.
  174. $buffer_size = $extensiondata['getINIEntries']['pdo_sqlsrv.client_buffer_max_kb_size'];
  175. $buffer_size_min = (12240 * 2);
  176. $buffer_size_ok = $buffer_size >= $buffer_size_min;
  177. if (!$buffer_size_ok) {
  178. drupal_set_message(t('pdo_sqlsrv.client_buffer_max_kb_size needs to be of at least @min, currently @current.',
  179. array('@min' => '24480Kb', '@current' => "{$buffer_size}Kb")), 'error');
  180. }
  181. // PDO version, and require at least 3.2.
  182. $version_ok = version_compare($extensiondata['getVersion'] , '3.2') >= 0;
  183. if (!$version_ok) {
  184. drupal_set_message(t('This version of the MS SQL Server driver needs at least the @min version of the SQL Server PDO, currently running @current. Download from <a href="!download">here</a>.',
  185. array(
  186. '@min' => '3.2',
  187. '@current' => $extensiondata['getVersion'],
  188. '!download' => 'http://www.microsoft.com/en-us/download/details.aspx?id=20098',
  189. ))
  190. , 'error');
  191. }
  192. // Check that Wincache user cache is enabled and big enough.
  193. $wincache_ok = (function_exists('wincache_ucache_info') && ($cache = @wincache_ucache_info(TRUE)) && ($meminfo = @wincache_ucache_meminfo()));
  194. if ($wincache_ok) {
  195. // Minimum 15 Mb of usercache.
  196. $wincache_ok = $meminfo['memory_total'] >= 20 * 1024 * 1024;
  197. }
  198. if (!$wincache_ok) {
  199. drupal_set_message(t('This version of the MS SQL Server needs the Wincache PHP extension with a minimum ucachesize of 20Mb.'), 'error');
  200. }
  201. // If there is something wrong do not allow the user to install.
  202. if (!$buffer_size_ok || !$version_ok || !$wincache_ok) {
  203. drupal_set_message(t('Please review the errors and refresh this page when fixed.'), 'status');
  204. }
  205. $form['messages']['errors'] = array(
  206. '#type' => 'markup',
  207. '#markup' => theme_status_messages(array('display' => NULL)),
  208. );
  209. if ($buffer_size_ok && $version_ok && $wincache_ok) {
  210. $form = array_merge($form, parent::getFormOptions($database));
  211. // Make username not required.
  212. $form['username']['#required'] = FALSE;
  213. // Add a description for about leaving username blank.
  214. $form['username']['#description'] = t('Leave username (and password) blank to use Windows authentication.');
  215. }
  216. return $form;
  217. }
  218. }