PageRenderTime 69ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php

https://github.com/Bancha/cakephp
PHP | 868 lines | 504 code | 92 blank | 272 comment | 0 complexity | 79758325af1d7f403a506e7662ccfae3 MD5 | raw file
  1. <?php
  2. /**
  3. * DboPostgresTest file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @package cake.libs
  16. * @since CakePHP(tm) v 1.2.0
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. App::uses('Model', 'Model');
  20. App::uses('AppModel', 'Model');
  21. App::uses('Postgres', 'Model/Datasource/Database');
  22. require_once dirname(dirname(dirname(__FILE__))) . DS . 'models.php';
  23. /**
  24. * DboPostgresTestDb class
  25. *
  26. * @package cake.tests.cases.libs.model.datasources
  27. */
  28. class DboPostgresTestDb extends Postgres {
  29. /**
  30. * simulated property
  31. *
  32. * @var array
  33. * @access public
  34. */
  35. public $simulated = array();
  36. /**
  37. * execute method
  38. *
  39. * @param mixed $sql
  40. * @access protected
  41. * @return void
  42. */
  43. function _execute($sql, $params = array()) {
  44. $this->simulated[] = $sql;
  45. return null;
  46. }
  47. /**
  48. * getLastQuery method
  49. *
  50. * @access public
  51. * @return void
  52. */
  53. function getLastQuery() {
  54. return $this->simulated[count($this->simulated) - 1];
  55. }
  56. }
  57. /**
  58. * PostgresTestModel class
  59. *
  60. * @package cake.tests.cases.libs.model.datasources
  61. */
  62. class PostgresTestModel extends Model {
  63. /**
  64. * name property
  65. *
  66. * @var string 'PostgresTestModel'
  67. * @access public
  68. */
  69. public $name = 'PostgresTestModel';
  70. /**
  71. * useTable property
  72. *
  73. * @var bool false
  74. * @access public
  75. */
  76. public $useTable = false;
  77. /**
  78. * belongsTo property
  79. *
  80. * @var array
  81. * @access public
  82. */
  83. public $belongsTo = array(
  84. 'PostgresClientTestModel' => array(
  85. 'foreignKey' => 'client_id'
  86. )
  87. );
  88. /**
  89. * find method
  90. *
  91. * @param mixed $conditions
  92. * @param mixed $fields
  93. * @param mixed $order
  94. * @param mixed $recursive
  95. * @access public
  96. * @return void
  97. */
  98. function find($conditions = null, $fields = null, $order = null, $recursive = null) {
  99. return $conditions;
  100. }
  101. /**
  102. * findAll method
  103. *
  104. * @param mixed $conditions
  105. * @param mixed $fields
  106. * @param mixed $order
  107. * @param mixed $recursive
  108. * @access public
  109. * @return void
  110. */
  111. function findAll($conditions = null, $fields = null, $order = null, $recursive = null) {
  112. return $conditions;
  113. }
  114. /**
  115. * schema method
  116. *
  117. * @access public
  118. * @return void
  119. */
  120. function schema($field = false) {
  121. return array(
  122. 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
  123. 'client_id' => array('type' => 'integer', 'null' => '', 'default' => '0', 'length' => '11'),
  124. 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
  125. 'login' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
  126. 'passwd' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
  127. 'addr_1' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
  128. 'addr_2' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '25'),
  129. 'zip_code' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
  130. 'city' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
  131. 'country' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
  132. 'phone' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
  133. 'fax' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
  134. 'url' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
  135. 'email' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
  136. 'comments' => array('type' => 'text', 'null' => '1', 'default' => '', 'length' => ''),
  137. 'last_login'=> array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => ''),
  138. 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
  139. 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
  140. );
  141. }
  142. }
  143. /**
  144. * PostgresClientTestModel class
  145. *
  146. * @package cake.tests.cases.libs.model.datasources
  147. */
  148. class PostgresClientTestModel extends Model {
  149. /**
  150. * name property
  151. *
  152. * @var string 'PostgresClientTestModel'
  153. * @access public
  154. */
  155. public $name = 'PostgresClientTestModel';
  156. /**
  157. * useTable property
  158. *
  159. * @var bool false
  160. * @access public
  161. */
  162. public $useTable = false;
  163. /**
  164. * schema method
  165. *
  166. * @access public
  167. * @return void
  168. */
  169. function schema($field = false) {
  170. return array(
  171. 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8', 'key' => 'primary'),
  172. 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
  173. 'email' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
  174. 'created' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => ''),
  175. 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
  176. );
  177. }
  178. }
  179. /**
  180. * DboPostgresTest class
  181. *
  182. * @package cake.tests.cases.libs.model.datasources.dbo
  183. */
  184. class DboPostgresTest extends CakeTestCase {
  185. /**
  186. * Do not automatically load fixtures for each test, they will be loaded manually
  187. * using CakeTestCase::loadFixtures
  188. *
  189. * @var boolean
  190. * @access public
  191. */
  192. public $autoFixtures = false;
  193. /**
  194. * Fixtures
  195. *
  196. * @var object
  197. * @access public
  198. */
  199. public $fixtures = array('core.user', 'core.binary_test', 'core.comment', 'core.article',
  200. 'core.tag', 'core.articles_tag', 'core.attachment', 'core.person', 'core.post', 'core.author',
  201. 'core.datatype',
  202. );
  203. /**
  204. * Actual DB connection used in testing
  205. *
  206. * @var DboSource
  207. * @access public
  208. */
  209. public $Dbo = null;
  210. /**
  211. * Simulated DB connection used in testing
  212. *
  213. * @var DboSource
  214. * @access public
  215. */
  216. public $Dbo2 = null;
  217. /**
  218. * Sets up a Dbo class instance for testing
  219. *
  220. */
  221. public function setUp() {
  222. Configure::write('Cache.disable', true);
  223. $this->Dbo = ConnectionManager::getDataSource('test');
  224. $this->skipIf(!($this->Dbo instanceof Postgres));
  225. $this->Dbo2 = new DboPostgresTestDb($this->Dbo->config, false);
  226. $this->model = new PostgresTestModel();
  227. }
  228. /**
  229. * Sets up a Dbo class instance for testing
  230. *
  231. */
  232. public function tearDown() {
  233. Configure::write('Cache.disable', false);
  234. unset($this->Dbo2);
  235. }
  236. /**
  237. * Test field quoting method
  238. *
  239. */
  240. public function testFieldQuoting() {
  241. $fields = array(
  242. '"PostgresTestModel"."id" AS "PostgresTestModel__id"',
  243. '"PostgresTestModel"."client_id" AS "PostgresTestModel__client_id"',
  244. '"PostgresTestModel"."name" AS "PostgresTestModel__name"',
  245. '"PostgresTestModel"."login" AS "PostgresTestModel__login"',
  246. '"PostgresTestModel"."passwd" AS "PostgresTestModel__passwd"',
  247. '"PostgresTestModel"."addr_1" AS "PostgresTestModel__addr_1"',
  248. '"PostgresTestModel"."addr_2" AS "PostgresTestModel__addr_2"',
  249. '"PostgresTestModel"."zip_code" AS "PostgresTestModel__zip_code"',
  250. '"PostgresTestModel"."city" AS "PostgresTestModel__city"',
  251. '"PostgresTestModel"."country" AS "PostgresTestModel__country"',
  252. '"PostgresTestModel"."phone" AS "PostgresTestModel__phone"',
  253. '"PostgresTestModel"."fax" AS "PostgresTestModel__fax"',
  254. '"PostgresTestModel"."url" AS "PostgresTestModel__url"',
  255. '"PostgresTestModel"."email" AS "PostgresTestModel__email"',
  256. '"PostgresTestModel"."comments" AS "PostgresTestModel__comments"',
  257. '"PostgresTestModel"."last_login" AS "PostgresTestModel__last_login"',
  258. '"PostgresTestModel"."created" AS "PostgresTestModel__created"',
  259. '"PostgresTestModel"."updated" AS "PostgresTestModel__updated"'
  260. );
  261. $result = $this->Dbo->fields($this->model);
  262. $expected = $fields;
  263. $this->assertEqual($expected, $result);
  264. $result = $this->Dbo->fields($this->model, null, 'PostgresTestModel.*');
  265. $expected = $fields;
  266. $this->assertEqual($expected, $result);
  267. $result = $this->Dbo->fields($this->model, null, array('*', 'AnotherModel.id', 'AnotherModel.name'));
  268. $expected = array_merge($fields, array(
  269. '"AnotherModel"."id" AS "AnotherModel__id"',
  270. '"AnotherModel"."name" AS "AnotherModel__name"'));
  271. $this->assertEqual($expected, $result);
  272. $result = $this->Dbo->fields($this->model, null, array('*', 'PostgresClientTestModel.*'));
  273. $expected = array_merge($fields, array(
  274. '"PostgresClientTestModel"."id" AS "PostgresClientTestModel__id"',
  275. '"PostgresClientTestModel"."name" AS "PostgresClientTestModel__name"',
  276. '"PostgresClientTestModel"."email" AS "PostgresClientTestModel__email"',
  277. '"PostgresClientTestModel"."created" AS "PostgresClientTestModel__created"',
  278. '"PostgresClientTestModel"."updated" AS "PostgresClientTestModel__updated"'));
  279. $this->assertEqual($expected, $result);
  280. }
  281. /**
  282. * testColumnParsing method
  283. *
  284. * @access public
  285. * @return void
  286. */
  287. function testColumnParsing() {
  288. $this->assertEqual($this->Dbo2->column('text'), 'text');
  289. $this->assertEqual($this->Dbo2->column('date'), 'date');
  290. $this->assertEqual($this->Dbo2->column('boolean'), 'boolean');
  291. $this->assertEqual($this->Dbo2->column('character varying'), 'string');
  292. $this->assertEqual($this->Dbo2->column('time without time zone'), 'time');
  293. $this->assertEqual($this->Dbo2->column('timestamp without time zone'), 'datetime');
  294. }
  295. /**
  296. * testValueQuoting method
  297. *
  298. * @access public
  299. * @return void
  300. */
  301. function testValueQuoting() {
  302. $this->assertEqual($this->Dbo->value(1.2, 'float'), "1.200000");
  303. $this->assertEqual($this->Dbo->value('1,2', 'float'), "'1,2'");
  304. $this->assertEqual($this->Dbo->value('0', 'integer'), "0");
  305. $this->assertEqual($this->Dbo->value('', 'integer'), 'NULL');
  306. $this->assertEqual($this->Dbo->value('', 'float'), 'NULL');
  307. $this->assertEqual($this->Dbo->value('', 'integer', false), "NULL");
  308. $this->assertEqual($this->Dbo->value('', 'float', false), "NULL");
  309. $this->assertEqual($this->Dbo->value('0.0', 'float'), "'0.0'");
  310. $this->assertEqual($this->Dbo->value('t', 'boolean'), "'TRUE'");
  311. $this->assertEqual($this->Dbo->value('f', 'boolean'), "'FALSE'");
  312. $this->assertEqual($this->Dbo->value(true), "'TRUE'");
  313. $this->assertEqual($this->Dbo->value(false), "'FALSE'");
  314. $this->assertEqual($this->Dbo->value('t'), "'t'");
  315. $this->assertEqual($this->Dbo->value('f'), "'f'");
  316. $this->assertEqual($this->Dbo->value('true', 'boolean'), "'TRUE'");
  317. $this->assertEqual($this->Dbo->value('false', 'boolean'), "'FALSE'");
  318. $this->assertEqual($this->Dbo->value('', 'boolean'), "'FALSE'");
  319. $this->assertEqual($this->Dbo->value(0, 'boolean'), "'FALSE'");
  320. $this->assertEqual($this->Dbo->value(1, 'boolean'), "'TRUE'");
  321. $this->assertEqual($this->Dbo->value('1', 'boolean'), "'TRUE'");
  322. $this->assertEqual($this->Dbo->value(null, 'boolean'), "NULL");
  323. $this->assertEqual($this->Dbo->value(array()), "NULL");
  324. }
  325. /**
  326. * test that localized floats don't cause trouble.
  327. *
  328. * @return void
  329. */
  330. function testLocalizedFloats() {
  331. $restore = setlocale(LC_ALL, null);
  332. setlocale(LC_ALL, 'de_DE');
  333. $result = $this->db->value(3.141593, 'float');
  334. $this->assertEqual((string)$result, "3.141593");
  335. $result = $this->db->value(3.14);
  336. $this->assertEqual((string)$result, "3.140000");
  337. setlocale(LC_ALL, $restore);
  338. }
  339. /**
  340. * test that date and time columns do not generate errors with null and nullish values.
  341. *
  342. * @return void
  343. */
  344. function testDateAndTimeAsNull() {
  345. $this->assertEqual($this->Dbo->value(null, 'date'), 'NULL');
  346. $this->assertEqual($this->Dbo->value('', 'date'), 'NULL');
  347. $this->assertEqual($this->Dbo->value('', 'datetime'), 'NULL');
  348. $this->assertEqual($this->Dbo->value(null, 'datetime'), 'NULL');
  349. $this->assertEqual($this->Dbo->value('', 'timestamp'), 'NULL');
  350. $this->assertEqual($this->Dbo->value(null, 'timestamp'), 'NULL');
  351. $this->assertEqual($this->Dbo->value('', 'time'), 'NULL');
  352. $this->assertEqual($this->Dbo->value(null, 'time'), 'NULL');
  353. }
  354. /**
  355. * Tests that different Postgres boolean 'flavors' are properly returned as native PHP booleans
  356. *
  357. * @access public
  358. * @return void
  359. */
  360. function testBooleanNormalization() {
  361. $this->assertEquals(true, $this->Dbo2->boolean('t', false));
  362. $this->assertEquals(true, $this->Dbo2->boolean('true', false));
  363. $this->assertEquals(true, $this->Dbo2->boolean('TRUE', false));
  364. $this->assertEquals(true, $this->Dbo2->boolean(true, false));
  365. $this->assertEquals(true, $this->Dbo2->boolean(1, false));
  366. $this->assertEquals(true, $this->Dbo2->boolean(" ", false));
  367. $this->assertEquals(false, $this->Dbo2->boolean('f', false));
  368. $this->assertEquals(false, $this->Dbo2->boolean('false', false));
  369. $this->assertEquals(false, $this->Dbo2->boolean('FALSE', false));
  370. $this->assertEquals(false, $this->Dbo2->boolean(false, false));
  371. $this->assertEquals(false, $this->Dbo2->boolean(0, false));
  372. $this->assertEquals(false, $this->Dbo2->boolean('', false));
  373. }
  374. /**
  375. * test that default -> false in schemas works correctly.
  376. *
  377. * @return void
  378. */
  379. function testBooleanDefaultFalseInSchema() {
  380. $this->loadFixtures('Datatype');
  381. $model = new Model(array('name' => 'Datatype', 'table' => 'datatypes', 'ds' => 'test'));
  382. $model->create();
  383. $this->assertIdentical(false, $model->data['Datatype']['bool']);
  384. }
  385. /**
  386. * testLastInsertIdMultipleInsert method
  387. *
  388. * @access public
  389. * @return void
  390. */
  391. function testLastInsertIdMultipleInsert() {
  392. $this->loadFixtures('User');
  393. $db1 = ConnectionManager::getDataSource('test');
  394. $table = $db1->fullTableName('users', false);
  395. $password = '5f4dcc3b5aa765d61d8327deb882cf99';
  396. $db1->execute(
  397. "INSERT INTO {$table} (\"user\", password) VALUES ('mariano', '{$password}')"
  398. );
  399. $this->assertEqual($db1->lastInsertId($table), 5);
  400. $db1->execute("INSERT INTO {$table} (\"user\", password) VALUES ('hoge', '{$password}')");
  401. $this->assertEqual($db1->lastInsertId($table), 6);
  402. }
  403. /**
  404. * Tests that table lists and descriptions are scoped to the proper Postgres schema
  405. *
  406. * @access public
  407. * @return void
  408. */
  409. function testSchemaScoping() {
  410. $db1 = ConnectionManager::getDataSource('test');
  411. $db1->cacheSources = false;
  412. $db1->reconnect(array('persistent' => false));
  413. $db1->query('CREATE SCHEMA _scope_test');
  414. $db2 = ConnectionManager::create(
  415. 'test_2',
  416. array_merge($db1->config, array('driver' => 'postgres', 'schema' => '_scope_test'))
  417. );
  418. $db2->cacheSources = false;
  419. $db2->query('DROP SCHEMA _scope_test');
  420. }
  421. /**
  422. * Tests that column types without default lengths in $columns do not have length values
  423. * applied when generating schemas.
  424. *
  425. * @access public
  426. * @return void
  427. */
  428. function testColumnUseLength() {
  429. $result = array('name' => 'foo', 'type' => 'string', 'length' => 100, 'default' => 'FOO');
  430. $expected = '"foo" varchar(100) DEFAULT \'FOO\'';
  431. $this->assertEqual($this->Dbo->buildColumn($result), $expected);
  432. $result = array('name' => 'foo', 'type' => 'text', 'length' => 100, 'default' => 'FOO');
  433. $expected = '"foo" text DEFAULT \'FOO\'';
  434. $this->assertEqual($this->Dbo->buildColumn($result), $expected);
  435. }
  436. /**
  437. * Tests that binary data is escaped/unescaped properly on reads and writes
  438. *
  439. * @access public
  440. * @return void
  441. */
  442. function testBinaryDataIntegrity() {
  443. $this->loadFixtures('BinaryTest');
  444. $data = '%PDF-1.3
  445. %ƒÂÚÂÎßÛƒ
  446. 4 0 obj
  447. << /Length 5 0 R /Filter /FlateDecode >>
  448. stream
  449. xµYMìΩ%)0¯îâ-«é]Q"πXµáÿ•Ip - P V,]Ú#c˚ˇ‰ut¥†∏Ti9 Ü=”›Ø_˜4>à∑‚Épcé¢Pxæ®2q\'
  450. 1UªbU áˇ+ö«[ıµão"R∑"HiGæä(å^Ãøsm?YlƒÃõªfiâEÚB&Î7^¸m°÷˛?2±Øsfiu#®Uˇú÷g¥C;ä")n})JºIÔ3ËSnÑÎ¥≤ıD∆¢∂Msx1üèG˚±Œ™⁄>¶ySïufØ ˝¸?UπÃã√6flÌÚC=øK?˝…s
  451. ˛§¯ˇ:-˜ò7ÓFæÕ˛V>ılflëÅd«ÜQdI ÎB%W¿ΩıÉn~h vêCS>«é˛(ØôK!¡zB!
  452. [œÜ"ûß ·iH¸[Àºæ∑¯¡L,ÀÚAlS∫ˆ=∫Œ≤cÄr&ˆÈ:√ÿ£˚È«4fl•À]vc›bÅôÿî=siXe4/¡p]ã]ôÆIœ™ Ωflà_ƒ‚G?«7 ùÿ ı¯K4ïIpV◊÷·\'éµóªÚæ>î
  453. ;!2¬F/fj£
  454. dw"IÊÜπ<ôÿˆ%IG1ytÛDflXg|Éòa§˜}C˛¿ÿe°G´Ú±jÍm~¿/∂hã<#-¥•ıùe87€t˜õ6w}´{æ
  455. mê ¡ 6\
  456. rAÀBùZ3aËr$G·$ó0Ñ üâUY4È¡%CŸ2rc<Iõ-.
  457. [ŒöâFAÉ+QglMÉîÉÄúÌ|¸»#x7¥«MgVÎ-G I?ÁLzwpHůnefqCî.nÕeèÿÛy¡˙fbüŒHÜAëÕNq=´@ cQdÖúAÉIqñŸ˘+2& Àù.ƒœ3EPƒOi:>ÍCäı
  458. =Õec=ëR˝eñ=<V$ì˙+x+¢ïÒÕ<àeWå»˚Õ d§&£àf ]fPA´âtënöåó Ë@K´÷˘}a_CI˚©yòHg,ôSSVìBƒl4 L.ÈYá,2íäÙ.$ó¸CäŸ*óy
  459. π?G,_·ÆÎç=^Vkvo±ó{§ƒ2»±¨Ïüo»ëD-ãé fió¥cVÙ\'™G~\'p¢%* ã˚÷
  460. ªºnh˚ºO^®[ÓÅfıÌF!(πT6`¬tΩÆ0ì»rTÎ`»Ñ«
  461. ]åp˝)=¿Ô0öVÂmˇˆø~¯ÁÔb*fc»ÎıÚ}tœsYÜaÆ˙X~<ÿ·Ù vé1p¿TDÔîÄúhˆ*Úîe)K p¨ÚJ3Ÿã>ÊuNê°Ü Ê9iÙ0˙AAEÍ ˙`∂£\'ûce•åƒX›ŸÁ´1SK{qdá"tÏ[wQ#SµBe∞∑µó…ÌV`B"Ñ≥„!è_Óφ-º*ºú¿Ë0ˆeê∂´ë+HFj…‡zvHÓN|ÔL÷ûñ3õÜ$z%sá…pÎóV38âs Çoµ•ß3†<9B·¨û~¢3)ÂxóÿÁCÕòÆ ∫Í=»ÿSπS;∆~±êÆTEp∑óÈ÷ÀuìDHÈ $ÉõæÜjû§"ÃONM®RËíRr{õS Êop±W;ÂUÔ PkÔˇflTæóflË ÆC©Ô[˚¨"ÆbF?ú%h˙ˇ4xèÕ(ó2ÙáíM])Ñd|=fë-cI0ñL¢kÖêk‰Rƒ«ıÄWñ8mO3∏&√æËX¯Hó—ì]yF2»–˜ádàà‡‹Çο„≥7mªHAS∑¶.;Œx(1} _kd©.fidç48M\'àáªCp^Krí<ɉXÓıïl!Ì$N<ı∞B»G]…∂Ó¯>˛ÔbõÒπÀ•:ôO<j∂™œ%âÏ—>@È$pÖu‹Ê´-QqV ?V≥JÆÍqÛX8(lπï@zgÖ}Fe<ˇ‡Sñ“ÿ˜ê?6‡L∫Oß~µ –?ËeäÚ®YîÕ =Ü=¢DÁu*GvBk;)L¬N«î:flö∂≠ÇΩq„Ñm하Ë∂‚"û§:±i^ΩÑ!)Wıyŧô á÷ÒôcsPdêãh˘ßHVç5fifiÈFçÌÛuçÖ/M=µ±ÿGû1coÔuñæz®. õ7ÉÏÜÆ,°HÍÉÌ7e º® íˆøNWKÂYµñé;µgV->µtË¥áßN2 ¯BaP-)eW.àôt^1CÖ?L&54jvãªZ ÷+4% ´0l»ú^°´© ûiπé®óܱÒÿïˆÌÆ19rQ=Í|ırMæ¬;òYé9. ˝V«ã¯,+ë®j*¡·/';
  462. $model = new AppModel(array('name' => 'BinaryTest', 'ds' => 'test'));
  463. $model->save(compact('data'));
  464. $result = $model->find('first');
  465. $this->assertEqual($result['BinaryTest']['data'], $data);
  466. }
  467. /**
  468. * Tests the syntax of generated schema indexes
  469. *
  470. * @access public
  471. * @return void
  472. */
  473. function testSchemaIndexSyntax() {
  474. $schema = new CakeSchema();
  475. $schema->tables = array('i18n' => array(
  476. 'id' => array(
  477. 'type' => 'integer', 'null' => false, 'default' => null,
  478. 'length' => 10, 'key' => 'primary'
  479. ),
  480. 'locale' => array('type'=>'string', 'null' => false, 'length' => 6, 'key' => 'index'),
  481. 'model' => array('type'=>'string', 'null' => false, 'key' => 'index'),
  482. 'foreign_key' => array(
  483. 'type'=>'integer', 'null' => false, 'length' => 10, 'key' => 'index'
  484. ),
  485. 'field' => array('type'=>'string', 'null' => false, 'key' => 'index'),
  486. 'content' => array('type'=>'text', 'null' => true, 'default' => null),
  487. 'indexes' => array(
  488. 'PRIMARY' => array('column' => 'id', 'unique' => 1),
  489. 'locale' => array('column' => 'locale', 'unique' => 0),
  490. 'model' => array('column' => 'model', 'unique' => 0),
  491. 'row_id' => array('column' => 'foreign_key', 'unique' => 0),
  492. 'field' => array('column' => 'field', 'unique' => 0)
  493. )
  494. ));
  495. $result = $this->Dbo->createSchema($schema);
  496. $this->assertNoPattern('/^CREATE INDEX(.+);,$/', $result);
  497. }
  498. /**
  499. * testCakeSchema method
  500. *
  501. * Test that schema generated postgresql queries are valid. ref #5696
  502. * Check that the create statement for a schema generated table is the same as the original sql
  503. *
  504. * @return void
  505. */
  506. public function testCakeSchema() {
  507. $db1 = ConnectionManager::getDataSource('test');
  508. $db1->cacheSources = false;
  509. $db1->reconnect(array('persistent' => false));
  510. $db1->rawQuery('CREATE TABLE ' . $db1->fullTableName('datatype_tests') . ' (
  511. id serial NOT NULL,
  512. "varchar" character varying(40) NOT NULL,
  513. "full_length" character varying NOT NULL,
  514. "timestamp" timestamp without time zone,
  515. "date" date,
  516. CONSTRAINT test_data_types_pkey PRIMARY KEY (id)
  517. )');
  518. $model = new Model(array('name' => 'DatatypeTest', 'ds' => 'test'));
  519. $schema = new CakeSchema(array('connection' => 'test'));
  520. $result = $schema->read(array(
  521. 'connection' => 'test',
  522. 'models' => array('DatatypeTest')
  523. ));
  524. $schema->tables = array('datatype_tests' => $result['tables']['missing']['datatype_tests']);
  525. $result = $db1->createSchema($schema, 'datatype_tests');
  526. $this->assertNoPattern('/timestamp DEFAULT/', $result);
  527. $this->assertPattern('/\"full_length\"\s*text\s.*,/', $result);
  528. $this->assertPattern('/timestamp\s*,/', $result);
  529. $db1->query('DROP TABLE ' . $db1->fullTableName('datatype_tests'));
  530. $db1->query($result);
  531. $result2 = $schema->read(array(
  532. 'connection' => 'test',
  533. 'models' => array('DatatypeTest')
  534. ));
  535. $schema->tables = array('datatype_tests' => $result2['tables']['missing']['datatype_tests']);
  536. $result2 = $db1->createSchema($schema, 'datatype_tests');
  537. $this->assertEqual($result, $result2);
  538. $db1->query('DROP TABLE ' . $db1->fullTableName('datatype_tests'));
  539. }
  540. /**
  541. * Test index generation from table info.
  542. *
  543. * @return void
  544. */
  545. function testIndexGeneration() {
  546. $name = $this->Dbo->fullTableName('index_test', false);
  547. $this->Dbo->query('CREATE TABLE ' . $name . ' ("id" serial NOT NULL PRIMARY KEY, "bool" integer, "small_char" varchar(50), "description" varchar(40) )');
  548. $this->Dbo->query('CREATE INDEX pointless_bool ON ' . $name . '("bool")');
  549. $this->Dbo->query('CREATE UNIQUE INDEX char_index ON ' . $name . '("small_char")');
  550. $expected = array(
  551. 'PRIMARY' => array('unique' => true, 'column' => 'id'),
  552. 'pointless_bool' => array('unique' => false, 'column' => 'bool'),
  553. 'char_index' => array('unique' => true, 'column' => 'small_char'),
  554. );
  555. $result = $this->Dbo->index($name);
  556. $this->Dbo->query('DROP TABLE ' . $name);
  557. $this->assertEqual($expected, $result);
  558. $name = $this->Dbo->fullTableName('index_test_2', false);
  559. $this->Dbo->query('CREATE TABLE ' . $name . ' ("id" serial NOT NULL PRIMARY KEY, "bool" integer, "small_char" varchar(50), "description" varchar(40) )');
  560. $this->Dbo->query('CREATE UNIQUE INDEX multi_col ON ' . $name . '("small_char", "bool")');
  561. $expected = array(
  562. 'PRIMARY' => array('unique' => true, 'column' => 'id'),
  563. 'multi_col' => array('unique' => true, 'column' => array('small_char', 'bool')),
  564. );
  565. $result = $this->Dbo->index($name);
  566. $this->Dbo->query('DROP TABLE ' . $name);
  567. $this->assertEqual($expected, $result);
  568. }
  569. /**
  570. * Test the alterSchema capabilities of postgres
  571. *
  572. * @access public
  573. * @return void
  574. */
  575. function testAlterSchema() {
  576. $Old = new CakeSchema(array(
  577. 'connection' => 'test',
  578. 'name' => 'AlterPosts',
  579. 'alter_posts' => array(
  580. 'id' => array('type' => 'integer', 'key' => 'primary'),
  581. 'author_id' => array('type' => 'integer', 'null' => false),
  582. 'title' => array('type' => 'string', 'null' => true),
  583. 'body' => array('type' => 'text'),
  584. 'published' => array('type' => 'string', 'length' => 1, 'default' => 'N'),
  585. 'created' => array('type' => 'datetime'),
  586. 'updated' => array('type' => 'datetime'),
  587. )
  588. ));
  589. $this->Dbo->query($this->Dbo->createSchema($Old));
  590. $New = new CakeSchema(array(
  591. 'connection' => 'test',
  592. 'name' => 'AlterPosts',
  593. 'alter_posts' => array(
  594. 'id' => array('type' => 'integer', 'key' => 'primary'),
  595. 'author_id' => array('type' => 'integer', 'null' => true),
  596. 'title' => array('type' => 'string', 'null' => false, 'default' => 'my title'),
  597. 'body' => array('type' => 'string', 'length' => 500),
  598. 'status' => array('type' => 'integer', 'length' => 3, 'default' => 1),
  599. 'created' => array('type' => 'datetime'),
  600. 'updated' => array('type' => 'datetime'),
  601. )
  602. ));
  603. $this->Dbo->query($this->Dbo->alterSchema($New->compare($Old), 'alter_posts'));
  604. $model = new CakeTestModel(array('table' => 'alter_posts', 'ds' => 'test'));
  605. $result = $model->schema();
  606. $this->assertTrue(isset($result['status']));
  607. $this->assertFalse(isset($result['published']));
  608. $this->assertEqual($result['body']['type'], 'string');
  609. $this->assertEqual($result['status']['default'], 1);
  610. $this->assertEqual($result['author_id']['null'], true);
  611. $this->assertEqual($result['title']['null'], false);
  612. $this->Dbo->query($this->Dbo->dropSchema($New));
  613. }
  614. /**
  615. * Test the alter index capabilities of postgres
  616. *
  617. * @access public
  618. * @return void
  619. */
  620. function testAlterIndexes() {
  621. $this->Dbo->cacheSources = false;
  622. $schema1 = new CakeSchema(array(
  623. 'name' => 'AlterTest1',
  624. 'connection' => 'test',
  625. 'altertest' => array(
  626. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  627. 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
  628. 'group1' => array('type' => 'integer', 'null' => true),
  629. 'group2' => array('type' => 'integer', 'null' => true)
  630. )
  631. ));
  632. $this->Dbo->rawQuery($this->Dbo->dropSchema($schema1));
  633. $this->Dbo->rawQuery($this->Dbo->createSchema($schema1));
  634. $schema2 = new CakeSchema(array(
  635. 'name' => 'AlterTest2',
  636. 'connection' => 'test',
  637. 'altertest' => array(
  638. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  639. 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
  640. 'group1' => array('type' => 'integer', 'null' => true),
  641. 'group2' => array('type' => 'integer', 'null' => true),
  642. 'indexes' => array(
  643. 'name_idx' => array('unique' => false, 'column' => 'name'),
  644. 'group_idx' => array('unique' => false, 'column' => 'group1'),
  645. 'compound_idx' => array('unique' => false, 'column' => array('group1', 'group2')),
  646. 'PRIMARY' => array('unique' => true, 'column' => 'id')
  647. )
  648. )
  649. ));
  650. $this->Dbo->query($this->Dbo->alterSchema($schema2->compare($schema1)));
  651. $indexes = $this->Dbo->index('altertest');
  652. $this->assertEqual($schema2->tables['altertest']['indexes'], $indexes);
  653. // Change three indexes, delete one and add another one
  654. $schema3 = new CakeSchema(array(
  655. 'name' => 'AlterTest3',
  656. 'connection' => 'test',
  657. 'altertest' => array(
  658. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  659. 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
  660. 'group1' => array('type' => 'integer', 'null' => true),
  661. 'group2' => array('type' => 'integer', 'null' => true),
  662. 'indexes' => array(
  663. 'name_idx' => array('unique' => true, 'column' => 'name'),
  664. 'group_idx' => array('unique' => false, 'column' => 'group2'),
  665. 'compound_idx' => array('unique' => false, 'column' => array('group2', 'group1')),
  666. 'another_idx' => array('unique' => false, 'column' => array('group1', 'name')))
  667. )));
  668. $this->Dbo->query($this->Dbo->alterSchema($schema3->compare($schema2)));
  669. $indexes = $this->Dbo->index('altertest');
  670. $this->assertEqual($schema3->tables['altertest']['indexes'], $indexes);
  671. // Compare us to ourself.
  672. $this->assertEqual($schema3->compare($schema3), array());
  673. // Drop the indexes
  674. $this->Dbo->query($this->Dbo->alterSchema($schema1->compare($schema3)));
  675. $indexes = $this->Dbo->index('altertest');
  676. $this->assertEqual(array(), $indexes);
  677. $this->Dbo->query($this->Dbo->dropSchema($schema1));
  678. }
  679. /*
  680. * Test it is possible to use virtual field with postgresql
  681. *
  682. * @access public
  683. * @return void
  684. */
  685. function testVirtualFields() {
  686. $this->loadFixtures('Article', 'Comment', 'User', 'Attachment', 'Tag', 'ArticlesTag');
  687. $Article = new Article;
  688. $Article->virtualFields = array(
  689. 'next_id' => 'Article.id + 1',
  690. 'complex' => 'Article.title || Article.body',
  691. 'functional' => 'COALESCE(User.user, Article.title)',
  692. 'subquery' => 'SELECT count(*) FROM ' . $Article->Comment->table
  693. );
  694. $result = $Article->find('first');
  695. $this->assertEqual($result['Article']['next_id'], 2);
  696. $this->assertEqual($result['Article']['complex'], $result['Article']['title'] . $result['Article']['body']);
  697. $this->assertEqual($result['Article']['functional'], $result['User']['user']);
  698. $this->assertEqual($result['Article']['subquery'], 6);
  699. }
  700. /**
  701. * Tests additional order options for postgres
  702. *
  703. * @access public
  704. * @return void
  705. */
  706. function testOrderAdditionalParams() {
  707. $result = $this->Dbo->order(array('title' => 'DESC NULLS FIRST', 'body' => 'DESC'));
  708. $expected = ' ORDER BY "title" DESC NULLS FIRST, "body" DESC';
  709. $this->assertEqual($expected, $result);
  710. }
  711. /**
  712. * Test it is possible to do a SELECT COUNT(DISTINCT Model.field) query in postgres and it gets correctly quoted
  713. */
  714. function testQuoteDistinctInFunction() {
  715. $this->loadFixtures('Article');
  716. $Article = new Article;
  717. $result = $this->Dbo->fields($Article, null, array('COUNT(DISTINCT Article.id)'));
  718. $expected = array('COUNT(DISTINCT "Article"."id")');
  719. $this->assertEqual($expected, $result);
  720. $result = $this->Dbo->fields($Article, null, array('COUNT(DISTINCT id)'));
  721. $expected = array('COUNT(DISTINCT "id")');
  722. $this->assertEqual($expected, $result);
  723. $result = $this->Dbo->fields($Article, null, array('COUNT(DISTINCT FUNC(id))'));
  724. $expected = array('COUNT(DISTINCT FUNC("id"))');
  725. $this->assertEqual($expected, $result);
  726. }
  727. /**
  728. * test that saveAll works even with conditions that lack a model name.
  729. *
  730. * @return void
  731. */
  732. function testUpdateAllWithNonQualifiedConditions() {
  733. $this->loadFixtures('Article');
  734. $Article = new Article();
  735. $result = $Article->updateAll(array('title' => "'Awesome'"), array('title' => 'Third Article'));
  736. $this->assertTrue($result);
  737. $result = $Article->find('count', array(
  738. 'conditions' => array('Article.title' => 'Awesome')
  739. ));
  740. $this->assertEqual($result, 1, 'Article count is wrong or fixture has changed.');
  741. }
  742. /**
  743. * test alterSchema on two tables.
  744. *
  745. * @return void
  746. */
  747. function testAlteringTwoTables() {
  748. $schema1 = new CakeSchema(array(
  749. 'name' => 'AlterTest1',
  750. 'connection' => 'test',
  751. 'altertest' => array(
  752. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  753. 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
  754. ),
  755. 'other_table' => array(
  756. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  757. 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
  758. )
  759. ));
  760. $schema2 = new CakeSchema(array(
  761. 'name' => 'AlterTest1',
  762. 'connection' => 'test',
  763. 'altertest' => array(
  764. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  765. 'field_two' => array('type' => 'string', 'null' => false, 'length' => 50),
  766. ),
  767. 'other_table' => array(
  768. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  769. 'field_two' => array('type' => 'string', 'null' => false, 'length' => 50),
  770. )
  771. ));
  772. $result = $this->db->alterSchema($schema2->compare($schema1));
  773. $this->assertEqual(2, substr_count($result, 'field_two'), 'Too many fields');
  774. $this->assertFalse(strpos(';ALTER', $result), 'Too many semi colons');
  775. }
  776. }