PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/include/database/MssqlHelper.php

https://github.com/vincentamari/SuperSweetAdmin
PHP | 777 lines | 542 code | 68 blank | 167 comment | 134 complexity | 4d98d46ecb0139685571d7c9a98984cb MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, AGPL-3.0, LGPL-2.1
  1. <?php
  2. if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
  3. /*********************************************************************************
  4. * SugarCRM is a customer relationship management program developed by
  5. * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it under
  8. * the terms of the GNU Affero General Public License version 3 as published by the
  9. * Free Software Foundation with the addition of the following permission added
  10. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  11. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  12. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  17. * details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License along with
  20. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  21. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22. * 02110-1301 USA.
  23. *
  24. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  25. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  26. *
  27. * The interactive user interfaces in modified source and object code versions
  28. * of this program must display Appropriate Legal Notices, as required under
  29. * Section 5 of the GNU Affero General Public License version 3.
  30. *
  31. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  32. * these Appropriate Legal Notices must retain the display of the "Powered by
  33. * SugarCRM" logo. If the display of the logo is not reasonably feasible for
  34. * technical reasons, the Appropriate Legal Notices must display the words
  35. * "Powered by SugarCRM".
  36. ********************************************************************************/
  37. /*********************************************************************************
  38. * Description: This file handles the Data base functionality for the application specific
  39. * to Mssql database. It is called by the DBManager class to generate various sql statements.
  40. *
  41. * All the functions in this class will work with any bean which implements the meta interface.
  42. * Please refer the DBManager documentation for the details.
  43. *
  44. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  45. * All Rights Reserved.
  46. * Contributor(s): ___RPS___________________________________..
  47. ********************************************************************************/
  48. include_once('include/database/DBHelper.php');
  49. class MssqlHelper extends DBHelper
  50. {
  51. /**
  52. * @see DBHelper::getColumnType()
  53. */
  54. public function getColumnType(
  55. $type,
  56. $name = '',
  57. $table = ''
  58. )
  59. {
  60. $map = array(
  61. 'int' => 'int',
  62. 'double' => 'float',
  63. 'float' => 'float',
  64. 'uint' => 'int',
  65. 'ulong' => 'int',
  66. 'long' => 'bigint',
  67. 'short' => 'smallint',
  68. 'varchar' => 'varchar',
  69. 'text' => 'text',
  70. 'longtext' => 'text',
  71. 'date' => 'datetime',
  72. 'enum' => 'varchar',
  73. 'relate' => 'varchar',
  74. 'multienum'=> 'text',
  75. 'html' => 'text',
  76. 'datetime' => 'datetime',
  77. 'datetimecombo' => 'datetime',
  78. 'time' => 'datetime',
  79. 'bool' => 'bit',
  80. 'tinyint' => 'tinyint',
  81. 'char' => 'char',
  82. 'blob' => 'image',
  83. 'longblob' => 'image',
  84. 'currency' => 'decimal(26,6)',
  85. 'decimal' => 'decimal',
  86. 'decimal2' => 'decimal',
  87. 'id' => 'varchar(36)',
  88. 'url'=>'varchar',
  89. 'encrypt'=>'varchar',
  90. 'file' => 'varchar',
  91. );
  92. return $map[$type];
  93. }
  94. /**
  95. * @see DBHelper::dropTableNameSQL()
  96. */
  97. public function dropTableNameSQL(
  98. $name
  99. )
  100. {
  101. return "DROP TABLE ".$name;
  102. }
  103. /**
  104. * Returns the SQL Alter table statment
  105. *
  106. * MSSQL has a quirky T-SQL alter table syntax. Pay special attention to the
  107. * modify operation
  108. * @param string $action
  109. * @param array $def
  110. * @param bool $ignorRequired
  111. * @param string $tablename
  112. */
  113. private function alterSQLRep(
  114. $action,
  115. array $def,
  116. $ignoreRequired,
  117. $tablename = ''
  118. )
  119. {
  120. switch($action){
  121. case 'add':
  122. $f_def=$this->oneColumnSQLRep($def, $ignoreRequired,$tablename,false);
  123. return "ADD " . $f_def;
  124. break;
  125. case 'drop':
  126. return "DROP COLUMN " . $def['name'];
  127. break;
  128. case 'modify':
  129. //You cannot specify a default value for a column for MSSQL
  130. $f_def = $this->oneColumnSQLRep($def, $ignoreRequired,$tablename, true);
  131. $f_stmt = "ALTER COLUMN ".$f_def['name'].' '.$f_def['colType'].' '.
  132. $f_def['required'].' '.$f_def['auto_increment']."\n";
  133. if (!empty( $f_def['default']))
  134. $f_stmt .= " ALTER TABLE " . $tablename . " ADD ". $f_def['default'] . " FOR " . $def['name'];
  135. return $f_stmt;
  136. break;
  137. default:
  138. return '';
  139. }
  140. }
  141. /**
  142. * @see DBHelper::changeColumnSQL()
  143. *
  144. * MSSQL uses a different syntax than MySQL for table altering that is
  145. * not quite as simplistic to implement...
  146. */
  147. protected function changeColumnSQL(
  148. $tablename,
  149. $fieldDefs,
  150. $action,
  151. $ignoreRequired = false
  152. )
  153. {
  154. $sql=$sql2='';
  155. $constraints = $this->get_field_default_constraint_name($tablename);
  156. if ($this->isFieldArray($fieldDefs)) {
  157. foreach ($fieldDefs as $def)
  158. {
  159. //if the column is being modified drop the default value
  160. //constraint if it exists. alterSQLRep will add the constraint back
  161. if (!empty($constraints[$def['name']])) {
  162. $sql.=" ALTER TABLE " . $tablename . " DROP CONSTRAINT " . $constraints[$def['name']];
  163. }
  164. //check to see if we need to drop related indexes before the alter
  165. $indices = $this->get_indices($tablename);
  166. foreach ( $indices as $index ) {
  167. if ( in_array($def['name'],$index['fields']) ) {
  168. $sql .= ' ' . $this->add_drop_constraint($tablename,$index,true).' ';
  169. $sql2 .= ' ' . $this->add_drop_constraint($tablename,$index,false).' ';
  170. }
  171. }
  172. $columns[] = $this->alterSQLRep($action, $def, $ignoreRequired,$tablename);
  173. }
  174. }
  175. else {
  176. //if the column is being modified drop the default value
  177. //constraint if it exists. alterSQLRep will add the constraint back
  178. if (!empty($constraints[$fieldDefs['name']])) {
  179. $sql.=" ALTER TABLE " . $tablename . " DROP CONSTRAINT " . $constraints[$fieldDefs['name']];
  180. }
  181. //check to see if we need to drop related indexes before the alter
  182. $indices = $this->get_indices($tablename);
  183. foreach ( $indices as $index ) {
  184. if ( in_array($fieldDefs['name'],$index['fields']) ) {
  185. $sql .= ' ' . $this->add_drop_constraint($tablename,$index,true).' ';
  186. $sql2 .= ' ' . $this->add_drop_constraint($tablename,$index,false).' ';
  187. }
  188. }
  189. $columns[] = $this->alterSQLRep($action, $fieldDefs, $ignoreRequired,$tablename);
  190. }
  191. $columns = implode(", ", $columns);
  192. $sql .= " ALTER TABLE $tablename $columns " . $sql2;
  193. return $sql;
  194. }
  195. /**
  196. * @see DBHelper::deleteColumnSQL()
  197. */
  198. public function deleteColumnSQL(
  199. SugarBean $bean,
  200. $fieldDefs
  201. )
  202. {
  203. if ($this->isFieldArray($fieldDefs))
  204. foreach ($fieldDefs as $fieldDef)
  205. $columns[] = $fieldDef['name'];
  206. else
  207. $columns[] = $fieldDefs['name'];
  208. return "ALTER TABLE ".$bean->getTableName()." DROP COLUMN ".implode(", DROP COLUMN ", $columns);
  209. }
  210. /**
  211. * returns an alter table statement to build the list of indices
  212. *
  213. * @param string $tableName
  214. * @param array $fieldDefs
  215. * @param array $indices
  216. * @return string SQL statement
  217. */
  218. public function indexSQL(
  219. $tableName,
  220. $fieldDefs,
  221. $indices
  222. )
  223. {
  224. // check if the passed value is an array of fields.
  225. // if not, convert it into an array
  226. if (!$this->isFieldArray($indices))
  227. $indices[] = $indices;
  228. $columns = array();
  229. foreach ($indices as $index) {
  230. if(!empty($index['db']) && $index['db'] != 'mssql')
  231. continue;
  232. if (isset($index['source']) && $index['source'] != 'db')
  233. continue;
  234. $type = $index['type'];
  235. $name = $index['name'];
  236. if (is_array($index['fields']))
  237. $fields = implode(", ", $index['fields']);
  238. else
  239. $fields = $index['fields'];
  240. switch ($type) {
  241. case 'primary':
  242. // SQL server requires primary key constraints to be created with
  243. // key word "PRIMARY KEY". Cannot default to index as synonym
  244. $columns[] = "ALTER TABLE $tableName ADD CONSTRAINT pk_$tableName PRIMARY KEY ($fields)";
  245. break;
  246. case 'unique':
  247. $columns[] = "ALTER TABLE $tableName ADD CONSTRAINT " . $index['name'] . " UNIQUE ($fields)";
  248. break;
  249. case 'clustered':
  250. $columns[] = "CREATE CLUSTERED INDEX $name ON $tableName ( $fields )";
  251. break;
  252. case 'index':
  253. case 'alternate_key':
  254. case 'foreign':
  255. $columns[] = "CREATE INDEX $name ON $tableName ( $fields )";
  256. break;
  257. case 'fulltext':
  258. if ($this->full_text_indexing_enabled()) {
  259. $catalog_name="sugar_fts_catalog";
  260. if ( isset($index['catalog_name'])
  261. && $index['catalog_name'] != 'default')
  262. $catalog_name = $index['catalog_name'];
  263. $language = "Language 1033";
  264. if (isset($index['language']) && !empty($index['language']))
  265. $language = "Language " . $index['language'];
  266. $key_index = $index['key_index'];;
  267. $change_tracking = "auto";
  268. if (isset($index['change_tracking'])
  269. && !empty($index['change_tracking']))
  270. $change_tracking = $index['change_tracking'];
  271. $columns[] = " CREATE FULLTEXT INDEX ON $tableName($fields $language) KEY INDEX $key_index ON $catalog_name WITH CHANGE_TRACKING $change_tracking" ;
  272. }
  273. break;
  274. }
  275. }
  276. $columns = implode(" ", $columns);
  277. return $columns;
  278. }
  279. protected function setAutoIncrement(
  280. $table,
  281. $field_name
  282. )
  283. {
  284. return "identity(1,1)";
  285. }
  286. /**
  287. * @see DBHelper::setAutoIncrementStart()
  288. */
  289. public function setAutoIncrementStart(
  290. $table,
  291. $field_name,
  292. $start_value
  293. )
  294. {
  295. if($start_value > 1)
  296. $start_value -= 1;
  297. $this->db->query("DBCC CHECKIDENT ('$table', RESEED, $start_value)");
  298. return true;
  299. }
  300. /**
  301. * @see DBHelper::getAutoIncrement()
  302. */
  303. public function getAutoIncrement(
  304. $table,
  305. $field_name
  306. )
  307. {
  308. $result = $this->db->query("select IDENT_CURRENT('$table') + IDENT_INCR ( '$table' ) as 'Auto_increment'");
  309. $row = $this->db->fetchByAssoc($result);
  310. if (!empty($row['Auto_increment']))
  311. return $row['Auto_increment'];
  312. return "";
  313. }
  314. /**
  315. * @see DBHelper::createTableSQLParams()
  316. */
  317. public function createTableSQLParams(
  318. $tablename,
  319. $fieldDefs,
  320. $indices,
  321. $engine = null
  322. )
  323. {
  324. if (empty($tablename) || empty($fieldDefs))
  325. return '';
  326. $sql ='';
  327. $columns = $this->columnSQLRep($fieldDefs, false, $tablename);
  328. if (empty($columns))
  329. return false;
  330. return "CREATE TABLE $tablename ($columns ) " .
  331. $this->indexSQL($tablename, $fieldDefs, $indices);
  332. }
  333. /**
  334. * @see DBHelper::get_indices()
  335. */
  336. public function get_indices(
  337. $tablename
  338. )
  339. {
  340. //find all unique indexes and primary keys.
  341. $query = <<<EOSQL
  342. SELECT LEFT(so.[name], 30) TableName,
  343. LEFT(si.[name], 50) 'Key_name',
  344. LEFT(sik.[keyno], 30) Sequence,
  345. LEFT(sc.[name], 30) Column_name,
  346. isunique = CASE
  347. WHEN si.status & 2 = 2 AND so.xtype != 'PK' THEN 1
  348. ELSE 0
  349. END
  350. FROM sysindexes si
  351. INNER JOIN sysindexkeys sik
  352. ON (si.[id] = sik.[id] AND si.indid = sik.indid)
  353. INNER JOIN sysobjects so
  354. ON si.[id] = so.[id]
  355. INNER JOIN syscolumns sc
  356. ON (so.[id] = sc.[id] AND sik.colid = sc.colid)
  357. INNER JOIN sysfilegroups sfg
  358. ON si.groupid = sfg.groupid
  359. WHERE so.[name] = '$tablename'
  360. ORDER BY Key_name, Sequence, Column_name
  361. EOSQL;
  362. $result = $this->db->query($query);
  363. $indices = array();
  364. while (($row=$this->db->fetchByAssoc($result)) != null) {
  365. $index_type = 'index';
  366. if ($row['Key_name'] == 'PRIMARY')
  367. $index_type = 'primary';
  368. elseif ($row['isunique'] == 1 )
  369. $index_type = 'unique';
  370. $name = strtolower($row['Key_name']);
  371. $indices[$name]['name'] = $name;
  372. $indices[$name]['type'] = $index_type;
  373. $indices[$name]['fields'][] = strtolower($row['Column_name']);
  374. }
  375. return $indices;
  376. }
  377. /**
  378. * @see DBHelper::get_columns()
  379. */
  380. public function get_columns(
  381. $tablename
  382. )
  383. {
  384. //find all unique indexes and primary keys.
  385. $result = $this->db->query("sp_columns $tablename");
  386. $columns = array();
  387. while (($row=$this->db->fetchByAssoc($result)) !=null) {
  388. $column_name = strtolower($row['COLUMN_NAME']);
  389. $columns[$column_name]['name']=$column_name;
  390. $columns[$column_name]['type']=strtolower($row['TYPE_NAME']);
  391. if ( $row['TYPE_NAME'] == 'decimal' ) {
  392. $columns[$column_name]['len']=strtolower($row['PRECISION']);
  393. $columns[$column_name]['len'].=','.strtolower($row['SCALE']);
  394. }
  395. elseif ( in_array($row['TYPE_NAME'],array('nchar','nvarchar')) )
  396. $columns[$column_name]['len']=strtolower($row['PRECISION']);
  397. elseif ( !in_array($row['TYPE_NAME'],array('datetime','text','bit')) )
  398. $columns[$column_name]['len']=strtolower($row['LENGTH']);
  399. if ( stristr($row['TYPE_NAME'],'identity') ) {
  400. $columns[$column_name]['auto_increment'] = '1';
  401. $columns[$column_name]['type']=str_replace(' identity','',strtolower($row['TYPE_NAME']));
  402. }
  403. if (!empty($row['IS_NULLABLE']) && $row['IS_NULLABLE'] == 'NO' && (empty($row['KEY']) || !stristr($row['KEY'],'PRI')))
  404. $columns[strtolower($row['COLUMN_NAME'])]['required'] = 'true';
  405. $column_def = 0;
  406. if ( strtolower($tablename) == 'relationships' ) {
  407. $column_def = $this->db->getOne("select cdefault from syscolumns where id = object_id('relationships') and name = '$column_name'");
  408. }
  409. if ( $column_def != 0 ) {
  410. $matches = array();
  411. $row['COLUMN_DEF'] = html_entity_decode($row['COLUMN_DEF'],ENT_QUOTES);
  412. if ( preg_match("/\([\(|'](.*)[\)|']\)/i",$row['COLUMN_DEF'],$matches) )
  413. $columns[$column_name]['default'] = $matches[1];
  414. elseif ( preg_match("/\(N'(.*)'\)/i",$row['COLUMN_DEF'],$matches) )
  415. $columns[$column_name]['default'] = $matches[1];
  416. else
  417. $columns[$column_name]['default'] = $row['COLUMN_DEF'];
  418. }
  419. }
  420. return $columns;
  421. }
  422. /**
  423. * @see DBHelper::add_drop_constraint()
  424. */
  425. public function add_drop_constraint(
  426. $table,
  427. $definition,
  428. $drop = false
  429. )
  430. {
  431. $type = $definition['type'];
  432. $fields = implode(',',$definition['fields']);
  433. $name = $definition['name'];
  434. $foreignTable = isset($definition['foreignTable']) ? $definition['foreignTable'] : array();
  435. $sql = '';
  436. switch ($type){
  437. // generic indices
  438. case 'index':
  439. case 'alternate_key':
  440. if ($drop)
  441. $sql = "DROP INDEX {$name} ON {$table}";
  442. else
  443. $sql = "CREATE INDEX {$name} ON {$table} ({$fields})";
  444. break;
  445. // constraints as indices
  446. case 'unique':
  447. if ($drop)
  448. $sql = "ALTER TABLE {$table} DROP CONSTRAINT $name";
  449. else
  450. $sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} UNIQUE ({$fields})";
  451. break;
  452. case 'primary':
  453. if ($drop)
  454. $sql = "ALTER TABLE {$table} DROP PRIMARY KEY";
  455. else
  456. $sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} PRIMARY KEY ({$fields})";
  457. break;
  458. case 'foreign':
  459. if ($drop)
  460. $sql = "ALTER TABLE {$table} DROP FOREIGN KEY ({$fields})";
  461. else
  462. $sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} FOREIGN KEY ({$fields}) REFERENCES {$foreignTable}({$foreignfields})";
  463. break;
  464. case 'fulltext':
  465. if ($this->full_text_indexing_enabled() && $drop)
  466. $sql = "DROP FULLTEXT INDEX ON {$table}";
  467. elseif ($this->full_text_indexing_enabled()) {
  468. $catalog_name="sugar_fts_catalog";
  469. if ( isset($index['catalog_name']) && $index['catalog_name'] != 'default')
  470. $catalog_name = $index['catalog_name'];
  471. $language = "Language 1033";
  472. if (isset($index['language']) && !empty($index['language']))
  473. $language = "Language " . $index['language'];
  474. $key_index = $index['key_index'];
  475. $change_tracking = "auto";
  476. if (isset($index['change_tracking']) && !empty($index['change_tracking']))
  477. $change_tracking = $index['change_tracking'];
  478. $columns[] = " CREATE FULLTEXT INDEX ON $table ($fields $language) KEY INDEX $key_index ON $catalog_name WITH CHANGE_TRACKING $change_tracking" ;
  479. }
  480. break;
  481. }
  482. return $sql;
  483. }
  484. /**
  485. * @see DBHelper::number_of_columns()
  486. */
  487. public function number_of_columns(
  488. $table_name
  489. )
  490. {
  491. $def_query = <<<EOSQL
  492. SELECT count(*) as cols
  493. FROM sys.columns col join sys.types col_type
  494. on col.user_type_id=col_type.user_type_id
  495. where col.object_id = (
  496. select object_id(sys.schemas.name + '.' + sys.tables.name)
  497. from sys.tables join sys.schemas
  498. on sys.schemas.schema_id = sys.tables.schema_id
  499. where sys.tables.name='$table_name'
  500. )
  501. EOSQL;
  502. /**
  503. * @TODO test the similarities of the above the query against all system tables vs the query below against
  504. * the information_schema view in terms of results and efficiency. suspician is provided the two produce
  505. * the same information the latter will be slightly faster.
  506. * <code>
  507. * <?php
  508. * $def_query = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='$table_name'";
  509. * ?>
  510. * </code>
  511. */
  512. $result = $this->db->query($def_query);
  513. $row = $this->db->fetchByAssoc($result);
  514. if (!empty($row)) {
  515. return $row['cols'];
  516. }
  517. return 0;
  518. }
  519. /**
  520. * Returns true if Full Text Search is installed
  521. *
  522. * @return bool
  523. */
  524. protected function full_text_indexing_installed()
  525. {
  526. $ftsChckRes = $this->db->query(
  527. "SELECT FULLTEXTSERVICEPROPERTY('IsFulltextInstalled') as fts");
  528. $row = $this->db->fetchByAssoc($ftsChckRes);
  529. return (isset($row) && isset($row['fts']) && ($row['fts'] == 1 || $row['fts'] == '1'));
  530. }
  531. /**
  532. * @see DBHelper::full_text_indexing_enabled()
  533. */
  534. protected function full_text_indexing_enabled(
  535. $dbname = null
  536. )
  537. {
  538. // check to see if we already have install setting in session
  539. if(!isset($_SESSION['IsFulltextInstalled']))
  540. $_SESSION['IsFulltextInstalled'] = $this->full_text_indexing_installed();
  541. // check to see if FTS Indexing service is installed
  542. if(empty($_SESSION['IsFulltextInstalled'])
  543. || $_SESSION['IsFulltextInstalled'] === false)
  544. return false;
  545. // grab the dbname if it was not passed through
  546. if (empty($dbname)) {
  547. global $sugar_config;
  548. $dbname = $sugar_config['dbconfig']['db_name'];
  549. }
  550. //we already know that Indexing service is installed, now check
  551. //to see if it is enabled
  552. $res = $this->db->query(
  553. "SELECT DATABASEPROPERTY('$dbname', 'IsFulltextEnabled') ftext");
  554. $row = $GLOBALS['db']->fetchByAssoc($res);
  555. return (isset($row['ftext']) && $row['ftext'] == 1);
  556. }
  557. /**
  558. * Creates default full text catalog
  559. */
  560. public function create_default_full_text_catalog()
  561. {
  562. if ($this->full_text_indexing_enabled()) {
  563. $GLOBALS['log']->debug('Creating the default catalog for full-text indexing, sugar_fts_catalog');
  564. //drop catalog if exists.
  565. $ret = $this->db->query("
  566. if not exists(
  567. select *
  568. from sys.fulltext_catalogs
  569. where name ='sugar_fts_catalog'
  570. )
  571. CREATE FULLTEXT CATALOG sugar_fts_catalog");
  572. if (empty($ret)) {
  573. $GLOBALS['log']->error('Error creating default full-text catalog, sugar_fts_catalog');
  574. }
  575. }
  576. }
  577. /**
  578. * Function returns name of the constraint automatically generated by sql-server.
  579. * We request this for default, primary key, required
  580. *
  581. * @param string $table
  582. * @param string $column
  583. * @return string
  584. */
  585. private function get_field_default_constraint_name(
  586. $table,
  587. $column = null
  588. )
  589. {
  590. static $results = array();
  591. if ( empty($column) && isset($results[$table]) )
  592. return $results[$table];
  593. $query = <<<EOQ
  594. select s.name, o.name, c.name dtrt, d.name ctrt
  595. from sys.default_constraints as d
  596. join sys.objects as o
  597. on o.object_id = d.parent_object_id
  598. join sys.columns as c
  599. on c.object_id = o.object_id and c.column_id = d.parent_column_id
  600. join sys.schemas as s
  601. on s.schema_id = o.schema_id
  602. where o.name = '$table'
  603. EOQ;
  604. if ( !empty($column) )
  605. $query .= " and c.name = '$column'";
  606. $res = $this->db->query($query);
  607. if ( !empty($column) ) {
  608. $row = $this->db->fetchByAssoc($res);
  609. if (!empty($row))
  610. return $row['ctrt'];
  611. }
  612. else {
  613. $returnResult = array();
  614. while ( $row = $this->db->fetchByAssoc($res) )
  615. $returnResult[$row['dtrt']] = $row['ctrt'];
  616. $results[$table] = $returnResult;
  617. return $returnResult;
  618. }
  619. return null;
  620. }
  621. /**
  622. * @see DBHelper::massageFieldDef()
  623. */
  624. public function massageFieldDef(
  625. &$fieldDef,
  626. $tablename
  627. )
  628. {
  629. parent::massageFieldDef($fieldDef,$tablename);
  630. if ($fieldDef['type'] == 'int')
  631. $fieldDef['len'] = '4';
  632. if ($fieldDef['type'] == 'bit' && empty($fieldDef['len']) )
  633. $fieldDef['len'] = '1';
  634. if ($fieldDef['type'] == 'bool' && empty($fieldDef['len']) )
  635. $fieldDef['len'] = '1';
  636. if ($fieldDef['type'] == 'float' && empty($fieldDef['len']) )
  637. $fieldDef['len'] = '8';
  638. if ($fieldDef['type'] == 'varchar' && empty($fieldDef['len']) )
  639. $fieldDef['len'] = '255';
  640. if ($fieldDef['type'] == 'nvarchar' && empty($fieldDef['len']) )
  641. $fieldDef['len'] = '255';
  642. if ($fieldDef['type'] == 'bit' && empty($fieldDef['default']) )
  643. $fieldDef['default'] = '0';
  644. if ($fieldDef['type'] == 'bool' && empty($fieldDef['default']) )
  645. $fieldDef['default'] = '0';
  646. if ($fieldDef['type'] == 'image' && empty($fieldDef['len']) )
  647. $fieldDef['len'] = '2147483647';
  648. if ($fieldDef['type'] == 'ntext' && empty($fieldDef['len']) )
  649. $fieldDef['len'] = '2147483646';
  650. if ($fieldDef['type'] == 'smallint' && empty($fieldDef['len']) )
  651. $fieldDef['len'] = '2';
  652. if (isset($fieldDef['required']) && $fieldDef['required'] && !isset($fieldDef['default']) )
  653. $fieldDef['default'] = '';
  654. }
  655. /**
  656. * @see DBHelper::oneColumnSQLRep()
  657. */
  658. protected function oneColumnSQLRep(
  659. $fieldDef,
  660. $ignoreRequired = false,
  661. $table = '',
  662. $return_as_array = false
  663. )
  664. {
  665. //Bug 25814
  666. if(isset($fieldDef['name'])){
  667. $name = $fieldDef['name'];
  668. $type = $this->getFieldType($fieldDef);
  669. $colType = $this->getColumnType($type, $name, $table);
  670. if(stristr($colType, 'decimal')){
  671. $fieldDef['len'] = isset($fieldDef['len'])? min($fieldDef['len'],38) : 38;
  672. }
  673. //bug: 39690 float(8) is interpreted as real and this generates a diff when doing repair
  674. if(stristr($colType, 'float')){
  675. if(isset($fieldDef['len']) && $fieldDef['len'] == 8){
  676. unset($fieldDef['len']);
  677. }
  678. }
  679. }
  680. $ref = parent::oneColumnSQLRep($fieldDef, $ignoreRequired, $table, true);
  681. // Bug 24307 - Don't add precision for float fields.
  682. if ( stristr($ref['colType'],'float') )
  683. $ref['colType'] = preg_replace('/(,\d+)/','',$ref['colType']);
  684. if ( $return_as_array )
  685. return $ref;
  686. else
  687. return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}";
  688. }
  689. /**
  690. * Saves changes to module's audit table
  691. *
  692. * @param object $bean Sugarbean instance
  693. * @param array $changes changes
  694. * @see DBHelper::getDataChanges()
  695. */
  696. public function save_audit_records(
  697. SugarBean &$bean,
  698. &$changes
  699. )
  700. {
  701. //Bug 25078 fixed by Martin Hu: sqlserver haven't 'date' type, trim extra "00:00:00"
  702. if($changes['data_type'] == 'date'){
  703. $changes['before'] = str_replace(' 00:00:00','',$changes['before']);
  704. }
  705. parent::save_audit_records($bean,$changes);
  706. }
  707. }
  708. ?>