PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/php/DB/mssql.php

https://bitbucket.org/adarshj/convenient_website
PHP | 914 lines | 406 code | 85 blank | 423 comment | 78 complexity | c98c8e70e6fc01e10acacb64e174e8f4 MD5 | raw file
Possible License(s): Apache-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-2-Clause, GPL-2.0, LGPL-3.0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * The PEAR DB driver for PHP's mssql extension
  5. * for interacting with Microsoft SQL Server databases
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * LICENSE: This source file is subject to version 3.0 of the PHP license
  10. * that is available through the world-wide-web at the following URI:
  11. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  12. * the PHP License and are unable to obtain it through the web, please
  13. * send a note to license@php.net so we can mail you a copy immediately.
  14. *
  15. * @category Database
  16. * @package DB
  17. * @author Sterling Hughes <sterling@php.net>
  18. * @author Daniel Convissor <danielc@php.net>
  19. * @copyright 1997-2005 The PHP Group
  20. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  21. * @version CVS: $Id: mssql.php,v 1.83 2005/03/07 18:24:51 danielc Exp $
  22. * @link http://pear.php.net/package/DB
  23. */
  24. /**
  25. * Obtain the DB_common class so it can be extended from
  26. */
  27. require_once 'DB/common.php';
  28. /**
  29. * The methods PEAR DB uses to interact with PHP's mssql extension
  30. * for interacting with Microsoft SQL Server databases
  31. *
  32. * These methods overload the ones declared in DB_common.
  33. *
  34. * @category Database
  35. * @package DB
  36. * @author Sterling Hughes <sterling@php.net>
  37. * @author Daniel Convissor <danielc@php.net>
  38. * @copyright 1997-2005 The PHP Group
  39. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  40. * @version Release: 1.7.6
  41. * @link http://pear.php.net/package/DB
  42. */
  43. class DB_mssql extends DB_common
  44. {
  45. // {{{ properties
  46. /**
  47. * The DB driver type (mysql, oci8, odbc, etc.)
  48. * @var string
  49. */
  50. var $phptype = 'mssql';
  51. /**
  52. * The database syntax variant to be used (db2, access, etc.), if any
  53. * @var string
  54. */
  55. var $dbsyntax = 'mssql';
  56. /**
  57. * The capabilities of this DB implementation
  58. *
  59. * The 'new_link' element contains the PHP version that first provided
  60. * new_link support for this DBMS. Contains false if it's unsupported.
  61. *
  62. * Meaning of the 'limit' element:
  63. * + 'emulate' = emulate with fetch row by number
  64. * + 'alter' = alter the query
  65. * + false = skip rows
  66. *
  67. * @var array
  68. */
  69. var $features = array(
  70. 'limit' => 'emulate',
  71. 'new_link' => false,
  72. 'numrows' => true,
  73. 'pconnect' => true,
  74. 'prepare' => false,
  75. 'ssl' => false,
  76. 'transactions' => true,
  77. );
  78. /**
  79. * A mapping of native error codes to DB error codes
  80. * @var array
  81. */
  82. // XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX
  83. var $errorcode_map = array(
  84. 110 => DB_ERROR_VALUE_COUNT_ON_ROW,
  85. 155 => DB_ERROR_NOSUCHFIELD,
  86. 170 => DB_ERROR_SYNTAX,
  87. 207 => DB_ERROR_NOSUCHFIELD,
  88. 208 => DB_ERROR_NOSUCHTABLE,
  89. 245 => DB_ERROR_INVALID_NUMBER,
  90. 515 => DB_ERROR_CONSTRAINT_NOT_NULL,
  91. 547 => DB_ERROR_CONSTRAINT,
  92. 1913 => DB_ERROR_ALREADY_EXISTS,
  93. 2627 => DB_ERROR_CONSTRAINT,
  94. 2714 => DB_ERROR_ALREADY_EXISTS,
  95. 3701 => DB_ERROR_NOSUCHTABLE,
  96. 8134 => DB_ERROR_DIVZERO,
  97. );
  98. /**
  99. * The raw database connection created by PHP
  100. * @var resource
  101. */
  102. var $connection;
  103. /**
  104. * The DSN information for connecting to a database
  105. * @var array
  106. */
  107. var $dsn = array();
  108. /**
  109. * Should data manipulation queries be committed automatically?
  110. * @var bool
  111. * @access private
  112. */
  113. var $autocommit = true;
  114. /**
  115. * The quantity of transactions begun
  116. *
  117. * {@internal While this is private, it can't actually be designated
  118. * private in PHP 5 because it is directly accessed in the test suite.}}
  119. *
  120. * @var integer
  121. * @access private
  122. */
  123. var $transaction_opcount = 0;
  124. /**
  125. * The database specified in the DSN
  126. *
  127. * It's a fix to allow calls to different databases in the same script.
  128. *
  129. * @var string
  130. * @access private
  131. */
  132. var $_db = null;
  133. // }}}
  134. // {{{ constructor
  135. /**
  136. * This constructor calls <kbd>$this->DB_common()</kbd>
  137. *
  138. * @return void
  139. */
  140. function DB_mssql()
  141. {
  142. $this->DB_common();
  143. }
  144. // }}}
  145. // {{{ connect()
  146. /**
  147. * Connect to the database server, log in and open the database
  148. *
  149. * Don't call this method directly. Use DB::connect() instead.
  150. *
  151. * @param array $dsn the data source name
  152. * @param bool $persistent should the connection be persistent?
  153. *
  154. * @return int DB_OK on success. A DB_Error object on failure.
  155. */
  156. function connect($dsn, $persistent = false)
  157. {
  158. if (!PEAR::loadExtension('mssql') && !PEAR::loadExtension('sybase')
  159. && !PEAR::loadExtension('sybase_ct'))
  160. {
  161. return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  162. }
  163. $this->dsn = $dsn;
  164. if ($dsn['dbsyntax']) {
  165. $this->dbsyntax = $dsn['dbsyntax'];
  166. }
  167. $params = array(
  168. $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost',
  169. $dsn['username'] ? $dsn['username'] : null,
  170. $dsn['password'] ? $dsn['password'] : null,
  171. );
  172. if ($dsn['port']) {
  173. $params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':')
  174. . $dsn['port'];
  175. }
  176. $connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
  177. $this->connection = @call_user_func_array($connect_function, $params);
  178. if (!$this->connection) {
  179. return $this->raiseError(DB_ERROR_CONNECT_FAILED,
  180. null, null, null,
  181. @mssql_get_last_message());
  182. }
  183. if ($dsn['database']) {
  184. if (!@mssql_select_db($dsn['database'], $this->connection)) {
  185. return $this->raiseError(DB_ERROR_NODBSELECTED,
  186. null, null, null,
  187. @mssql_get_last_message());
  188. }
  189. $this->_db = $dsn['database'];
  190. }
  191. return DB_OK;
  192. }
  193. // }}}
  194. // {{{ disconnect()
  195. /**
  196. * Disconnects from the database server
  197. *
  198. * @return bool TRUE on success, FALSE on failure
  199. */
  200. function disconnect()
  201. {
  202. $ret = @mssql_close($this->connection);
  203. $this->connection = null;
  204. return $ret;
  205. }
  206. // }}}
  207. // {{{ simpleQuery()
  208. /**
  209. * Sends a query to the database server
  210. *
  211. * @param string the SQL query string
  212. *
  213. * @return mixed + a PHP result resrouce for successful SELECT queries
  214. * + the DB_OK constant for other successful queries
  215. * + a DB_Error object on failure
  216. */
  217. function simpleQuery($query)
  218. {
  219. $ismanip = DB::isManip($query);
  220. $this->last_query = $query;
  221. if (!@mssql_select_db($this->_db, $this->connection)) {
  222. return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
  223. }
  224. $query = $this->modifyQuery($query);
  225. if (!$this->autocommit && $ismanip) {
  226. if ($this->transaction_opcount == 0) {
  227. $result = @mssql_query('BEGIN TRAN', $this->connection);
  228. if (!$result) {
  229. return $this->mssqlRaiseError();
  230. }
  231. }
  232. $this->transaction_opcount++;
  233. }
  234. $result = @mssql_query($query, $this->connection);
  235. if (!$result) {
  236. return $this->mssqlRaiseError();
  237. }
  238. // Determine which queries that should return data, and which
  239. // should return an error code only.
  240. return $ismanip ? DB_OK : $result;
  241. }
  242. // }}}
  243. // {{{ nextResult()
  244. /**
  245. * Move the internal mssql result pointer to the next available result
  246. *
  247. * @param a valid fbsql result resource
  248. *
  249. * @access public
  250. *
  251. * @return true if a result is available otherwise return false
  252. */
  253. function nextResult($result)
  254. {
  255. return @mssql_next_result($result);
  256. }
  257. // }}}
  258. // {{{ fetchInto()
  259. /**
  260. * Places a row from the result set into the given array
  261. *
  262. * Formating of the array and the data therein are configurable.
  263. * See DB_result::fetchInto() for more information.
  264. *
  265. * This method is not meant to be called directly. Use
  266. * DB_result::fetchInto() instead. It can't be declared "protected"
  267. * because DB_result is a separate object.
  268. *
  269. * @param resource $result the query result resource
  270. * @param array $arr the referenced array to put the data in
  271. * @param int $fetchmode how the resulting array should be indexed
  272. * @param int $rownum the row number to fetch (0 = first row)
  273. *
  274. * @return mixed DB_OK on success, NULL when the end of a result set is
  275. * reached or on failure
  276. *
  277. * @see DB_result::fetchInto()
  278. */
  279. function fetchInto($result, &$arr, $fetchmode, $rownum = null)
  280. {
  281. if ($rownum !== null) {
  282. if (!@mssql_data_seek($result, $rownum)) {
  283. return null;
  284. }
  285. }
  286. if ($fetchmode & DB_FETCHMODE_ASSOC) {
  287. $arr = @mssql_fetch_array($result, MSSQL_ASSOC);
  288. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  289. $arr = array_change_key_case($arr, CASE_LOWER);
  290. }
  291. } else {
  292. $arr = @mssql_fetch_row($result);
  293. }
  294. if (!$arr) {
  295. return null;
  296. }
  297. if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  298. $this->_rtrimArrayValues($arr);
  299. }
  300. if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  301. $this->_convertNullArrayValuesToEmpty($arr);
  302. }
  303. return DB_OK;
  304. }
  305. // }}}
  306. // {{{ freeResult()
  307. /**
  308. * Deletes the result set and frees the memory occupied by the result set
  309. *
  310. * This method is not meant to be called directly. Use
  311. * DB_result::free() instead. It can't be declared "protected"
  312. * because DB_result is a separate object.
  313. *
  314. * @param resource $result PHP's query result resource
  315. *
  316. * @return bool TRUE on success, FALSE if $result is invalid
  317. *
  318. * @see DB_result::free()
  319. */
  320. function freeResult($result)
  321. {
  322. return @mssql_free_result($result);
  323. }
  324. // }}}
  325. // {{{ numCols()
  326. /**
  327. * Gets the number of columns in a result set
  328. *
  329. * This method is not meant to be called directly. Use
  330. * DB_result::numCols() instead. It can't be declared "protected"
  331. * because DB_result is a separate object.
  332. *
  333. * @param resource $result PHP's query result resource
  334. *
  335. * @return int the number of columns. A DB_Error object on failure.
  336. *
  337. * @see DB_result::numCols()
  338. */
  339. function numCols($result)
  340. {
  341. $cols = @mssql_num_fields($result);
  342. if (!$cols) {
  343. return $this->mssqlRaiseError();
  344. }
  345. return $cols;
  346. }
  347. // }}}
  348. // {{{ numRows()
  349. /**
  350. * Gets the number of rows in a result set
  351. *
  352. * This method is not meant to be called directly. Use
  353. * DB_result::numRows() instead. It can't be declared "protected"
  354. * because DB_result is a separate object.
  355. *
  356. * @param resource $result PHP's query result resource
  357. *
  358. * @return int the number of rows. A DB_Error object on failure.
  359. *
  360. * @see DB_result::numRows()
  361. */
  362. function numRows($result)
  363. {
  364. $rows = @mssql_num_rows($result);
  365. if ($rows === false) {
  366. return $this->mssqlRaiseError();
  367. }
  368. return $rows;
  369. }
  370. // }}}
  371. // {{{ autoCommit()
  372. /**
  373. * Enables or disables automatic commits
  374. *
  375. * @param bool $onoff true turns it on, false turns it off
  376. *
  377. * @return int DB_OK on success. A DB_Error object if the driver
  378. * doesn't support auto-committing transactions.
  379. */
  380. function autoCommit($onoff = false)
  381. {
  382. // XXX if $this->transaction_opcount > 0, we should probably
  383. // issue a warning here.
  384. $this->autocommit = $onoff ? true : false;
  385. return DB_OK;
  386. }
  387. // }}}
  388. // {{{ commit()
  389. /**
  390. * Commits the current transaction
  391. *
  392. * @return int DB_OK on success. A DB_Error object on failure.
  393. */
  394. function commit()
  395. {
  396. if ($this->transaction_opcount > 0) {
  397. if (!@mssql_select_db($this->_db, $this->connection)) {
  398. return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
  399. }
  400. $result = @mssql_query('COMMIT TRAN', $this->connection);
  401. $this->transaction_opcount = 0;
  402. if (!$result) {
  403. return $this->mssqlRaiseError();
  404. }
  405. }
  406. return DB_OK;
  407. }
  408. // }}}
  409. // {{{ rollback()
  410. /**
  411. * Reverts the current transaction
  412. *
  413. * @return int DB_OK on success. A DB_Error object on failure.
  414. */
  415. function rollback()
  416. {
  417. if ($this->transaction_opcount > 0) {
  418. if (!@mssql_select_db($this->_db, $this->connection)) {
  419. return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
  420. }
  421. $result = @mssql_query('ROLLBACK TRAN', $this->connection);
  422. $this->transaction_opcount = 0;
  423. if (!$result) {
  424. return $this->mssqlRaiseError();
  425. }
  426. }
  427. return DB_OK;
  428. }
  429. // }}}
  430. // {{{ affectedRows()
  431. /**
  432. * Determines the number of rows affected by a data maniuplation query
  433. *
  434. * 0 is returned for queries that don't manipulate data.
  435. *
  436. * @return int the number of rows. A DB_Error object on failure.
  437. */
  438. function affectedRows()
  439. {
  440. if (DB::isManip($this->last_query)) {
  441. $res = @mssql_query('select @@rowcount', $this->connection);
  442. if (!$res) {
  443. return $this->mssqlRaiseError();
  444. }
  445. $ar = @mssql_fetch_row($res);
  446. if (!$ar) {
  447. $result = 0;
  448. } else {
  449. @mssql_free_result($res);
  450. $result = $ar[0];
  451. }
  452. } else {
  453. $result = 0;
  454. }
  455. return $result;
  456. }
  457. // }}}
  458. // {{{ nextId()
  459. /**
  460. * Returns the next free id in a sequence
  461. *
  462. * @param string $seq_name name of the sequence
  463. * @param boolean $ondemand when true, the seqence is automatically
  464. * created if it does not exist
  465. *
  466. * @return int the next id number in the sequence.
  467. * A DB_Error object on failure.
  468. *
  469. * @see DB_common::nextID(), DB_common::getSequenceName(),
  470. * DB_mssql::createSequence(), DB_mssql::dropSequence()
  471. */
  472. function nextId($seq_name, $ondemand = true)
  473. {
  474. $seqname = $this->getSequenceName($seq_name);
  475. if (!@mssql_select_db($this->_db, $this->connection)) {
  476. return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
  477. }
  478. $repeat = 0;
  479. do {
  480. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  481. $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
  482. $this->popErrorHandling();
  483. if ($ondemand && DB::isError($result) &&
  484. ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
  485. {
  486. $repeat = 1;
  487. $result = $this->createSequence($seq_name);
  488. if (DB::isError($result)) {
  489. return $this->raiseError($result);
  490. }
  491. } elseif (!DB::isError($result)) {
  492. $result =& $this->query("SELECT @@IDENTITY FROM $seqname");
  493. $repeat = 0;
  494. } else {
  495. $repeat = false;
  496. }
  497. } while ($repeat);
  498. if (DB::isError($result)) {
  499. return $this->raiseError($result);
  500. }
  501. $result = $result->fetchRow(DB_FETCHMODE_ORDERED);
  502. return $result[0];
  503. }
  504. /**
  505. * Creates a new sequence
  506. *
  507. * @param string $seq_name name of the new sequence
  508. *
  509. * @return int DB_OK on success. A DB_Error object on failure.
  510. *
  511. * @see DB_common::createSequence(), DB_common::getSequenceName(),
  512. * DB_mssql::nextID(), DB_mssql::dropSequence()
  513. */
  514. function createSequence($seq_name)
  515. {
  516. return $this->query('CREATE TABLE '
  517. . $this->getSequenceName($seq_name)
  518. . ' ([id] [int] IDENTITY (1, 1) NOT NULL,'
  519. . ' [vapor] [int] NULL)');
  520. }
  521. // }}}
  522. // {{{ dropSequence()
  523. /**
  524. * Deletes a sequence
  525. *
  526. * @param string $seq_name name of the sequence to be deleted
  527. *
  528. * @return int DB_OK on success. A DB_Error object on failure.
  529. *
  530. * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  531. * DB_mssql::nextID(), DB_mssql::createSequence()
  532. */
  533. function dropSequence($seq_name)
  534. {
  535. return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
  536. }
  537. // }}}
  538. // {{{ quoteIdentifier()
  539. /**
  540. * Quotes a string so it can be safely used as a table or column name
  541. *
  542. * @param string $str identifier name to be quoted
  543. *
  544. * @return string quoted identifier string
  545. *
  546. * @see DB_common::quoteIdentifier()
  547. * @since Method available since Release 1.6.0
  548. */
  549. function quoteIdentifier($str)
  550. {
  551. return '[' . str_replace(']', ']]', $str) . ']';
  552. }
  553. // }}}
  554. // {{{ mssqlRaiseError()
  555. /**
  556. * Produces a DB_Error object regarding the current problem
  557. *
  558. * @param int $errno if the error is being manually raised pass a
  559. * DB_ERROR* constant here. If this isn't passed
  560. * the error information gathered from the DBMS.
  561. *
  562. * @return object the DB_Error object
  563. *
  564. * @see DB_common::raiseError(),
  565. * DB_mssql::errorNative(), DB_mssql::errorCode()
  566. */
  567. function mssqlRaiseError($code = null)
  568. {
  569. $message = @mssql_get_last_message();
  570. if (!$code) {
  571. $code = $this->errorNative();
  572. }
  573. return $this->raiseError($this->errorCode($code, $message),
  574. null, null, null, "$code - $message");
  575. }
  576. // }}}
  577. // {{{ errorNative()
  578. /**
  579. * Gets the DBMS' native error code produced by the last query
  580. *
  581. * @return int the DBMS' error code
  582. */
  583. function errorNative()
  584. {
  585. $res = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
  586. if (!$res) {
  587. return DB_ERROR;
  588. }
  589. $row = @mssql_fetch_row($res);
  590. return $row[0];
  591. }
  592. // }}}
  593. // {{{ errorCode()
  594. /**
  595. * Determines PEAR::DB error code from mssql's native codes.
  596. *
  597. * If <var>$nativecode</var> isn't known yet, it will be looked up.
  598. *
  599. * @param mixed $nativecode mssql error code, if known
  600. * @return integer an error number from a DB error constant
  601. * @see errorNative()
  602. */
  603. function errorCode($nativecode = null, $msg = '')
  604. {
  605. if (!$nativecode) {
  606. $nativecode = $this->errorNative();
  607. }
  608. if (isset($this->errorcode_map[$nativecode])) {
  609. if ($nativecode == 3701
  610. && preg_match('/Cannot drop the index/i', $msg))
  611. {
  612. return DB_ERROR_NOT_FOUND;
  613. }
  614. return $this->errorcode_map[$nativecode];
  615. } else {
  616. return DB_ERROR;
  617. }
  618. }
  619. // }}}
  620. // {{{ tableInfo()
  621. /**
  622. * Returns information about a table or a result set
  623. *
  624. * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  625. * is a table name.
  626. *
  627. * @param object|string $result DB_result object from a query or a
  628. * string containing the name of a table.
  629. * While this also accepts a query result
  630. * resource identifier, this behavior is
  631. * deprecated.
  632. * @param int $mode a valid tableInfo mode
  633. *
  634. * @return array an associative array with the information requested.
  635. * A DB_Error object on failure.
  636. *
  637. * @see DB_common::tableInfo()
  638. */
  639. function tableInfo($result, $mode = null)
  640. {
  641. if (is_string($result)) {
  642. /*
  643. * Probably received a table name.
  644. * Create a result resource identifier.
  645. */
  646. if (!@mssql_select_db($this->_db, $this->connection)) {
  647. return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
  648. }
  649. $id = @mssql_query("SELECT * FROM $result WHERE 1=0",
  650. $this->connection);
  651. $got_string = true;
  652. } elseif (isset($result->result)) {
  653. /*
  654. * Probably received a result object.
  655. * Extract the result resource identifier.
  656. */
  657. $id = $result->result;
  658. $got_string = false;
  659. } else {
  660. /*
  661. * Probably received a result resource identifier.
  662. * Copy it.
  663. * Deprecated. Here for compatibility only.
  664. */
  665. $id = $result;
  666. $got_string = false;
  667. }
  668. if (!is_resource($id)) {
  669. return $this->mssqlRaiseError(DB_ERROR_NEED_MORE_DATA);
  670. }
  671. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  672. $case_func = 'strtolower';
  673. } else {
  674. $case_func = 'strval';
  675. }
  676. $count = @mssql_num_fields($id);
  677. $res = array();
  678. if ($mode) {
  679. $res['num_fields'] = $count;
  680. }
  681. for ($i = 0; $i < $count; $i++) {
  682. $res[$i] = array(
  683. 'table' => $got_string ? $case_func($result) : '',
  684. 'name' => $case_func(@mssql_field_name($id, $i)),
  685. 'type' => @mssql_field_type($id, $i),
  686. 'len' => @mssql_field_length($id, $i),
  687. // We only support flags for table
  688. 'flags' => $got_string
  689. ? $this->_mssql_field_flags($result,
  690. @mssql_field_name($id, $i))
  691. : '',
  692. );
  693. if ($mode & DB_TABLEINFO_ORDER) {
  694. $res['order'][$res[$i]['name']] = $i;
  695. }
  696. if ($mode & DB_TABLEINFO_ORDERTABLE) {
  697. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  698. }
  699. }
  700. // free the result only if we were called on a table
  701. if ($got_string) {
  702. @mssql_free_result($id);
  703. }
  704. return $res;
  705. }
  706. // }}}
  707. // {{{ _mssql_field_flags()
  708. /**
  709. * Get a column's flags
  710. *
  711. * Supports "not_null", "primary_key",
  712. * "auto_increment" (mssql identity), "timestamp" (mssql timestamp),
  713. * "unique_key" (mssql unique index, unique check or primary_key) and
  714. * "multiple_key" (multikey index)
  715. *
  716. * mssql timestamp is NOT similar to the mysql timestamp so this is maybe
  717. * not useful at all - is the behaviour of mysql_field_flags that primary
  718. * keys are alway unique? is the interpretation of multiple_key correct?
  719. *
  720. * @param string $table the table name
  721. * @param string $column the field name
  722. *
  723. * @return string the flags
  724. *
  725. * @access private
  726. * @author Joern Barthel <j_barthel@web.de>
  727. */
  728. function _mssql_field_flags($table, $column)
  729. {
  730. static $tableName = null;
  731. static $flags = array();
  732. if ($table != $tableName) {
  733. $flags = array();
  734. $tableName = $table;
  735. // get unique and primary keys
  736. $res = $this->getAll("EXEC SP_HELPINDEX[$table]", DB_FETCHMODE_ASSOC);
  737. foreach ($res as $val) {
  738. $keys = explode(', ', $val['index_keys']);
  739. if (sizeof($keys) > 1) {
  740. foreach ($keys as $key) {
  741. $this->_add_flag($flags[$key], 'multiple_key');
  742. }
  743. }
  744. if (strpos($val['index_description'], 'primary key')) {
  745. foreach ($keys as $key) {
  746. $this->_add_flag($flags[$key], 'primary_key');
  747. }
  748. } elseif (strpos($val['index_description'], 'unique')) {
  749. foreach ($keys as $key) {
  750. $this->_add_flag($flags[$key], 'unique_key');
  751. }
  752. }
  753. }
  754. // get auto_increment, not_null and timestamp
  755. $res = $this->getAll("EXEC SP_COLUMNS[$table]", DB_FETCHMODE_ASSOC);
  756. foreach ($res as $val) {
  757. $val = array_change_key_case($val, CASE_LOWER);
  758. if ($val['nullable'] == '0') {
  759. $this->_add_flag($flags[$val['column_name']], 'not_null');
  760. }
  761. if (strpos($val['type_name'], 'identity')) {
  762. $this->_add_flag($flags[$val['column_name']], 'auto_increment');
  763. }
  764. if (strpos($val['type_name'], 'timestamp')) {
  765. $this->_add_flag($flags[$val['column_name']], 'timestamp');
  766. }
  767. }
  768. }
  769. if (array_key_exists($column, $flags)) {
  770. return(implode(' ', $flags[$column]));
  771. }
  772. return '';
  773. }
  774. // }}}
  775. // {{{ _add_flag()
  776. /**
  777. * Adds a string to the flags array if the flag is not yet in there
  778. * - if there is no flag present the array is created
  779. *
  780. * @param array &$array the reference to the flag-array
  781. * @param string $value the flag value
  782. *
  783. * @return void
  784. *
  785. * @access private
  786. * @author Joern Barthel <j_barthel@web.de>
  787. */
  788. function _add_flag(&$array, $value)
  789. {
  790. if (!is_array($array)) {
  791. $array = array($value);
  792. } elseif (!in_array($value, $array)) {
  793. array_push($array, $value);
  794. }
  795. }
  796. // }}}
  797. // {{{ getSpecialQuery()
  798. /**
  799. * Obtains the query string needed for listing a given type of objects
  800. *
  801. * @param string $type the kind of objects you want to retrieve
  802. *
  803. * @return string the SQL query string or null if the driver doesn't
  804. * support the object type requested
  805. *
  806. * @access protected
  807. * @see DB_common::getListOf()
  808. */
  809. function getSpecialQuery($type)
  810. {
  811. switch ($type) {
  812. case 'tables':
  813. return "SELECT name FROM sysobjects WHERE type = 'U'"
  814. . ' ORDER BY name';
  815. case 'views':
  816. return "SELECT name FROM sysobjects WHERE type = 'V'";
  817. default:
  818. return null;
  819. }
  820. }
  821. // }}}
  822. }
  823. /*
  824. * Local variables:
  825. * tab-width: 4
  826. * c-basic-offset: 4
  827. * End:
  828. */
  829. ?>