# Source for file Mssql.php

Documentation is available at Mssql.php

1. <?php
2. /*
3. * $Id: Mssql.php 1178 2007-03-18 20:00:45Z zYne $
4. *
5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16. *
17. * This software consists of voluntary contributions made by many individuals
18. * and is licensed under the LGPL. For more information, see
19. * <http://www.phpdoctrine.com>.
20. */
21. Doctrine::autoload('Doctrine_Connection');
22. /**
23. * Doctrine_Connection_Mssql
24. *
25. * @package Doctrine
26. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
27. * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
28. * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
29. * @version $Revision: 1178 $
30. * @category Object Relational Mapping
31. * @link www.phpdoctrine.com
32. * @since 1.0
33. */
34. class Doctrine_Connection_Mssql extends Doctrine_Connection
35. {
36. /**
37. * @var string $driverName the name of this connection driver
38. */
39. protected $driverName = 'Mssql';
40. /**
41. * the constructor
42. *
43. * @param Doctrine_Manager $manager
44. * @param PDO $pdo database handle
45. */
46. public function __construct(Doctrine_Manager $manager, $adapter)
47. {
48. // initialize all driver options
49. $this->supported = array(
50. 'sequences' => 'emulated',
51. 'indexes' => true,
52. 'affected_rows' => true,
53. 'transactions' => true,
54. 'summary_functions' => true,
55. 'order_by_text' => true,
56. 'current_id' => 'emulated',
57. 'limit_queries' => 'emulated',
58. 'LOBs' => true,
59. 'replace' => 'emulated',
60. 'sub_selects' => true,
61. 'auto_increment' => true,
62. 'primary_key' => true,
63. 'result_introspection' => true,
64. 'prepared_statements' => 'emulated',
65. );
67. parent::__construct($manager, $adapter);
68. }
69. /**
70. * quoteIdentifier
71. * Quote a string so it can be safely used as a table / column name
72. *
73. * Quoting style depends on which database driver is being used.
74. *
75. * @param string $identifier identifier name to be quoted
76. * @param bool $checkOption check the 'quote_identifier' option
77. *
78. * @return string quoted identifier string
79. */
80. public function quoteIdentifier($identifier, $checkOption = false)
81. {
82. if ($checkOption && ! $this->getAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER)) {
83. return $identifier;
84. }
85. return '[' . str_replace(']', ']]', $identifier) . ']';
86. }
87. /**
88. * Adds an adapter-specific LIMIT clause to the SELECT statement.
89. * [ borrowed from Zend Framework ]
90. *
91. * @param string $query
92. * @param mixed $limit
93. * @param mixed $offset
94. * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
95. * @return string
96. */
97. public function modifyLimitQuery($query, $limit, $offset, $isManip = false)
98. {
99. if ($limit > 0) {
100. $count = intval($limit);
102. $offset = intval($offset);
103. if ($offset < 0) {
104. throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
105. }
107. $orderby = stristr($query, 'ORDER BY');
108. if ($orderby !== false) {
109. $sort = (stripos($orderby, 'desc') !== false) ? 'desc' : 'asc';
110. $order = str_ireplace('ORDER BY', '', $orderby);
111. $order = trim(preg_replace('/ASC|DESC/i', '', $order));
112. }
114. $query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($count+$offset) . ' ', $query);
116. $query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS inner_tbl';
117. if ($orderby !== false) {
118. $query .= ' ORDER BY ' . $order . ' ';
119. $query .= (stripos($sort, 'asc') !== false) ? 'DESC' : 'ASC';
120. }
121. $query .= ') AS outer_tbl';
122. if ($orderby !== false) {
123. $query .= ' ORDER BY ' . $order . ' ' . $sort;
124. }
126. return $query;
128. }
130. return $query;
131. }
132. /**
133. * return version information about the server
134. *
135. * @param bool $native determines if the raw version string should be returned
136. * @return mixed array/string with version information or MDB2 error object
137. */
138. public function getServerVersion($native = false)
139. {
140. if ($this->serverInfo) {
141. $serverInfo = $this->serverInfo;
142. } else {
143. $query = 'SELECT @@VERSION';
144. $serverInfo = $this->fetchOne($query);
145. }
146. // cache server_info
147. $this->serverInfo = $serverInfo;
148. if ( ! $native) {
149. if (preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $serverInfo, $tmp)) {
150. $serverInfo = array(
151. 'major' => $tmp[1],
152. 'minor' => $tmp[2],
153. 'patch' => $tmp[3],
154. 'extra' => null,
155. 'native' => $serverInfo,
156. );
157. } else {
158. $serverInfo = array(
159. 'major' => null,
160. 'minor' => null,
161. 'patch' => null,
162. 'extra' => null,
163. 'native' => $serverInfo,
164. );
165. }
166. }
167. return $serverInfo;
168. }
169. /**
170. * Checks if there's a sequence that exists.
171. *
172. * @param string $seq_name The sequence name to verify.
173. * @return boolean The value if the table exists or not
174. */
175. public function checkSequence($seqName)
176. {
177. $query = 'SELECT * FROM ' . $seqName;
178. try {
179. $this->exec($query);
180. } catch(Doctrine_Connection_Exception $e) {
181. if ($e->getPortableCode() == Doctrine::ERR_NOSUCHTABLE) {
182. return false;
183. }
185. throw $e;
186. }
187. return true;
188. }
189. }