/libraries/cms/schema/changeitemsqlsrv.php

https://github.com/rvsjoen/joomla-cms · PHP · 164 lines · 88 code · 11 blank · 65 comment · 15 complexity · 968b113e13553695ba4ad136cb420e03 MD5 · raw file

  1. <?php
  2. /**
  3. * @package CMS.Library
  4. * @subpackage Schema
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('_JEXEC') or die;
  10. /**
  11. * Checks the database schema against one MySQL DDL query to see if it has been run.
  12. *
  13. * @package CMS.Library
  14. * @subpackage Schema
  15. * @since 2.5
  16. */
  17. class JSchemaChangeitemsqlsrv extends JSchemaChangeitem
  18. {
  19. /**
  20. * Checks a DDL query to see if it is a known type
  21. * If yes, build a check query to see if the DDL has been run on the database.
  22. * If successful, the $msgElements, $queryType, $checkStatus and $checkQuery fields are populated.
  23. * The $msgElements contains the text to create the user message.
  24. * The $checkQuery contains the SQL query to check whether the schema change has
  25. * been run against the current database. The $queryType contains the type of
  26. * DDL query that was run (for example, CREATE_TABLE, ADD_COLUMN, CHANGE_COLUMN_TYPE, ADD_INDEX).
  27. * The $checkStatus field is set to zero if the query is created
  28. *
  29. * If not successful, $checkQuery is empty and , and $checkStatus is -1.
  30. * For example, this will happen if the current line is a non-DDL statement.
  31. *
  32. * @return void
  33. *
  34. * @since 2.5
  35. */
  36. protected function buildCheckQuery()
  37. {
  38. // Initialize fields in case we can't create a check query
  39. $this->checkStatus = -1; // change status to skipped
  40. $result = null;
  41. // Remove any newlines
  42. $this->updateQuery = str_replace("\n", '', $this->updateQuery);
  43. // Fix up extra spaces around () and in general
  44. $find = array('#((\s*)\(\s*([^)\s]+)\s*)(\))#','#(\s)(\s*)#');
  45. $replace = array('($3)', '$1');
  46. $updateQuery = preg_replace($find, $replace, $this->updateQuery);
  47. $wordArray = explode(' ', $updateQuery);
  48. // First, make sure we have an array of at least 6 elements
  49. // if not, we can't make a check query for this one
  50. if (count($wordArray) < 6)
  51. {
  52. // Done with method
  53. return;
  54. }
  55. // We can only make check queries for alter table and create table queries
  56. $command = strtoupper($wordArray[0] . ' ' . $wordArray[1]);
  57. if ($command === 'ALTER TABLE')
  58. {
  59. $alterCommand = strtoupper($wordArray[3] . ' ' . $wordArray[4]);
  60. if ($alterCommand == 'ADD')
  61. {
  62. $result = 'SELECT * FROM INFORMATION_SCHEMA.Columns ' . $wordArray[2] .
  63. ' WHERE COLUMN_NAME = ' . $this->fixQuote($wordArray[5]);
  64. $this->queryType = 'ADD';
  65. $this->msgElements = array($this->fixQuote($wordArray[2]), $this->fixQuote($wordArray[5]));
  66. }
  67. elseif ($alterCommand == 'CREATE INDEX')
  68. {
  69. $index = $this->fixQuote(substr($wordArray[5], 0, strpos($wordArray[5], '(')));
  70. $result = 'SELECT * FROM SYS.INDEXES ' . $wordArray[2] . ' WHERE name = ' . $index;
  71. $this->queryType = 'CREATE INDEX';
  72. $this->msgElements = array($this->fixQuote($wordArray[2]), $index);
  73. }
  74. elseif (strtoupper($wordArray[3]) == 'MODIFY')
  75. {
  76. $type = $this->fixQuote($wordArray[5]);
  77. if (isset($wordArray[6]))
  78. {
  79. $type = $this->fixQuote($this->fixInteger($wordArray[5], $wordArray[6]));
  80. }
  81. $result = 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ' . $this->fixQuote($wordArray[2]);
  82. $this->queryType = 'ALTER COLUMN COLUMN_NAME =' . $this->fixQuote($wordArray[4]);
  83. $this->msgElements = array($this->fixQuote($wordArray[2]), $this->fixQuote($wordArray[4]));
  84. }
  85. elseif (strtoupper($wordArray[3]) == 'CHANGE')
  86. {
  87. // Kludge to fix problem with "integer unsigned"
  88. $type = $this->fixQuote($this->fixInteger($wordArray[6], $wordArray[7]));
  89. $result = 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ' . $this->fixQuote($wordArray[2]);
  90. $this->fixQuote($wordArray[4]);
  91. $this->queryType = 'ALTER COLUMN COLUMN_NAME =' . $this->fixQuote($wordArray[4]);
  92. $this->msgElements = array($this->fixQuote($wordArray[2]), $this->fixQuote($wordArray[4]));
  93. }
  94. }
  95. if ($command == 'CREATE TABLE')
  96. {
  97. $table = $wordArray[5];
  98. $result = 'SELECT * FROM sys.TABLES WHERE NAME = ' . $this->fixQuote($table);
  99. $this->queryType = 'CREATE_TABLE';
  100. $this->msgElements = array($this->fixQuote($table));
  101. }
  102. // Set fields based on results
  103. if ($this->checkQuery = $result)
  104. {
  105. // Unchecked status
  106. $this->checkStatus = 0;
  107. }
  108. else
  109. {
  110. // Skipped
  111. $this->checkStatus = -1;
  112. }
  113. }
  114. /**
  115. * Fix up integer. Fixes problem with MySQL integer descriptions.
  116. * If you change a column to "integer unsigned" it shows
  117. * as "int(10) unsigned" in the check query.
  118. *
  119. * @param string $type1 the column type
  120. * @param string $type2 the column attributes
  121. *
  122. * @return string The original or changed column type.
  123. *
  124. * @since 2.5
  125. */
  126. private function fixInteger($type1, $type2)
  127. {
  128. $result = $type1;
  129. if (strtolower($type1) == "integer" && strtolower(substr($type2, 0, 8)) == 'unsigned')
  130. {
  131. $result = 'int';
  132. }
  133. return $result;
  134. }
  135. /**
  136. * Fixes up a string for inclusion in a query.
  137. * Replaces name quote character with normal quote for literal.
  138. * Drops trailing semi-colon. Injects the database prefix.
  139. *
  140. * @param string $string The input string to be cleaned up.
  141. *
  142. * @return string The modified string.
  143. *
  144. * @since 2.5
  145. */
  146. private function fixQuote($string)
  147. {
  148. $string = str_replace('`', '', $string);
  149. $string = str_replace(';', '', $string);
  150. $string = str_replace('#__', $this->db->getPrefix(), $string);
  151. return $this->db->quote($string);
  152. }
  153. }