Parser2.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. <?php /* vim: se et ts=4 sw=4 sts=4 fdm=marker tw=80: */
  2. /**
  3. * Copyright (c) 1998-2010 Manuel Lemos, Tomas V.V.Cox,
  4. * Stig. S. Bakken, Lukas Smith, Igor Feghali
  5. * All rights reserved.
  6. *
  7. * MDB2_Schema enables users to maintain RDBMS independant schema files
  8. * in XML that can be used to manipulate both data and database schemas
  9. * This LICENSE is in the BSD license style.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. *
  15. * Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. *
  18. * Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in the
  20. * documentation and/or other materials provided with the distribution.
  21. *
  22. * Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,
  23. * Lukas Smith, Igor Feghali nor the names of his contributors may be
  24. * used to endorse or promote products derived from this software
  25. * without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  30. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  31. * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  32. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  33. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  34. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  35. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  37. * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * PHP version 5
  41. *
  42. * @category Database
  43. * @package MDB2_Schema
  44. * @author Igor Feghali <ifeghali@php.net>
  45. * @license BSD http://www.opensource.org/licenses/bsd-license.php
  46. * @version SVN: $Id$
  47. * @link http://pear.php.net/packages/MDB2_Schema
  48. */
  49. require_once 'XML/Unserializer.php';
  50. require_once 'MDB2/Schema/Validate.php';
  51. /**
  52. * Parses an XML schema file
  53. *
  54. * @category Database
  55. * @package MDB2_Schema
  56. * @author Lukas Smith <smith@pooteeweet.org>
  57. * @author Igor Feghali <ifeghali@php.net>
  58. * @license BSD http://www.opensource.org/licenses/bsd-license.php
  59. * @link http://pear.php.net/packages/MDB2_Schema
  60. */
  61. class MDB2_Schema_Parser2 extends XML_Unserializer
  62. {
  63. var $database_definition = array();
  64. var $database_loaded = array();
  65. var $variables = array();
  66. var $error;
  67. var $structure = false;
  68. var $val;
  69. var $options = array();
  70. var $table = array();
  71. var $table_name = '';
  72. var $field = array();
  73. var $field_name = '';
  74. var $index = array();
  75. var $index_name = '';
  76. var $constraint = array();
  77. var $constraint_name = '';
  78. var $sequence = array();
  79. var $sequence_name = '';
  80. var $init = array();
  81. /**
  82. * PHP 5 constructor
  83. *
  84. * @param array $variables mixed array with user defined schema
  85. * variables
  86. * @param bool $fail_on_invalid_names array with reserved words per RDBMS
  87. * @param array $structure multi dimensional array with
  88. * database schema and data
  89. * @param array $valid_types information of all valid fields
  90. * types
  91. * @param bool $force_defaults if true sets a default value to
  92. * field when not explicit
  93. * @param int $max_identifiers_length maximum allowed size for entities
  94. * name
  95. *
  96. * @return void
  97. *
  98. * @access public
  99. * @static
  100. */
  101. function __construct($variables, $fail_on_invalid_names = true,
  102. $structure = false, $valid_types = array(), $force_defaults = true,
  103. $max_identifiers_length = null
  104. ) {
  105. // force ISO-8859-1 due to different defaults for PHP4 and PHP5
  106. // todo: this probably needs to be investigated some more and cleaned up
  107. $this->options['encoding'] = 'ISO-8859-1';
  108. $this->options['XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE'] = true;
  109. $this->options['XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY'] = false;
  110. $this->options['forceEnum'] = array('table', 'field', 'index', 'foreign', 'insert', 'update', 'delete', 'sequence');
  111. /*
  112. * todo: find a way to force the following items not to be parsed as arrays
  113. * as it cause problems in functions with multiple arguments
  114. */
  115. //$this->options['forceNEnum'] = array('value', 'column');
  116. $this->variables = $variables;
  117. $this->structure = $structure;
  118. $this->val = new MDB2_Schema_Validate($fail_on_invalid_names, $valid_types, $force_defaults);
  119. parent::XML_Unserializer($this->options);
  120. }
  121. /**
  122. * Main method. Parses XML Schema File.
  123. *
  124. * @return bool|error object
  125. *
  126. * @access public
  127. */
  128. function parse()
  129. {
  130. $result = $this->unserialize($this->filename, true);
  131. if (PEAR::isError($result)) {
  132. return $result;
  133. } else {
  134. $this->database_loaded = $this->getUnserializedData();
  135. return $this->fixDatabaseKeys($this->database_loaded);
  136. }
  137. }
  138. /**
  139. * Do the necessary stuff to set the input XML schema file
  140. *
  141. * @param string $filename full path to schema file
  142. *
  143. * @return boolean MDB2_OK on success
  144. *
  145. * @access public
  146. */
  147. function setInputFile($filename)
  148. {
  149. $this->filename = $filename;
  150. return MDB2_OK;
  151. }
  152. /**
  153. * Enforce the default values for mandatory keys and ensure everything goes
  154. * always in the same order (simulates the behaviour of the original
  155. * parser). Works at database level.
  156. *
  157. * @param array $database multi dimensional array with database definition
  158. * and data.
  159. *
  160. * @return bool|error MDB2_OK on success or error object
  161. *
  162. * @access private
  163. */
  164. function fixDatabaseKeys($database)
  165. {
  166. $this->database_definition = array(
  167. 'name' => '',
  168. 'create' => '',
  169. 'overwrite' => '',
  170. 'charset' => '',
  171. 'description' => '',
  172. 'comments' => '',
  173. 'tables' => array(),
  174. 'sequences' => array()
  175. );
  176. if (!empty($database['name'])) {
  177. $this->database_definition['name'] = $database['name'];
  178. }
  179. if (!empty($database['create'])) {
  180. $this->database_definition['create'] = $database['create'];
  181. }
  182. if (!empty($database['overwrite'])) {
  183. $this->database_definition['overwrite'] = $database['overwrite'];
  184. }
  185. if (!empty($database['charset'])) {
  186. $this->database_definition['charset'] = $database['charset'];
  187. }
  188. if (!empty($database['description'])) {
  189. $this->database_definition['description'] = $database['description'];
  190. }
  191. if (!empty($database['comments'])) {
  192. $this->database_definition['comments'] = $database['comments'];
  193. }
  194. if (!empty($database['table']) && is_array($database['table'])) {
  195. foreach ($database['table'] as $table) {
  196. $this->fixTableKeys($table);
  197. }
  198. }
  199. if (!empty($database['sequence']) && is_array($database['sequence'])) {
  200. foreach ($database['sequence'] as $sequence) {
  201. $this->fixSequenceKeys($sequence);
  202. }
  203. }
  204. $result = $this->val->validateDatabase($this->database_definition);
  205. if (PEAR::isError($result)) {
  206. return $this->raiseError($result->getUserinfo());
  207. }
  208. return MDB2_OK;
  209. }
  210. /**
  211. * Enforce the default values for mandatory keys and ensure everything goes
  212. * always in the same order (simulates the behaviour of the original
  213. * parser). Works at table level.
  214. *
  215. * @param array $table multi dimensional array with table definition
  216. * and data.
  217. *
  218. * @return bool|error MDB2_OK on success or error object
  219. *
  220. * @access private
  221. */
  222. function fixTableKeys($table)
  223. {
  224. $this->table = array(
  225. 'was' => '',
  226. 'description' => '',
  227. 'comments' => '',
  228. 'fields' => array(),
  229. 'indexes' => array(),
  230. 'constraints' => array(),
  231. 'initialization' => array()
  232. );
  233. if (!empty($table['name'])) {
  234. $this->table_name = $table['name'];
  235. } else {
  236. $this->table_name = '';
  237. }
  238. if (!empty($table['was'])) {
  239. $this->table['was'] = $table['was'];
  240. }
  241. if (!empty($table['description'])) {
  242. $this->table['description'] = $table['description'];
  243. }
  244. if (!empty($table['comments'])) {
  245. $this->table['comments'] = $table['comments'];
  246. }
  247. if (!empty($table['declaration']) && is_array($table['declaration'])) {
  248. if (!empty($table['declaration']['field']) && is_array($table['declaration']['field'])) {
  249. foreach ($table['declaration']['field'] as $field) {
  250. $this->fixTableFieldKeys($field);
  251. }
  252. }
  253. if (!empty($table['declaration']['index']) && is_array($table['declaration']['index'])) {
  254. foreach ($table['declaration']['index'] as $index) {
  255. $this->fixTableIndexKeys($index);
  256. }
  257. }
  258. if (!empty($table['declaration']['foreign']) && is_array($table['declaration']['foreign'])) {
  259. foreach ($table['declaration']['foreign'] as $constraint) {
  260. $this->fixTableConstraintKeys($constraint);
  261. }
  262. }
  263. }
  264. if (!empty($table['initialization']) && is_array($table['initialization'])) {
  265. if (!empty($table['initialization']['insert']) && is_array($table['initialization']['insert'])) {
  266. foreach ($table['initialization']['insert'] as $init) {
  267. $this->fixTableInitializationKeys($init, 'insert');
  268. }
  269. }
  270. if (!empty($table['initialization']['update']) && is_array($table['initialization']['update'])) {
  271. foreach ($table['initialization']['update'] as $init) {
  272. $this->fixTableInitializationKeys($init, 'update');
  273. }
  274. }
  275. if (!empty($table['initialization']['delete']) && is_array($table['initialization']['delete'])) {
  276. foreach ($table['initialization']['delete'] as $init) {
  277. $this->fixTableInitializationKeys($init, 'delete');
  278. }
  279. }
  280. }
  281. $result = $this->val->validateTable($this->database_definition['tables'], $this->table, $this->table_name);
  282. if (PEAR::isError($result)) {
  283. return $this->raiseError($result->getUserinfo());
  284. } else {
  285. $this->database_definition['tables'][$this->table_name] = $this->table;
  286. }
  287. return MDB2_OK;
  288. }
  289. /**
  290. * Enforce the default values for mandatory keys and ensure everything goes
  291. * always in the same order (simulates the behaviour of the original
  292. * parser). Works at table field level.
  293. *
  294. * @param array $field array with table field definition
  295. *
  296. * @return bool|error MDB2_OK on success or error object
  297. *
  298. * @access private
  299. */
  300. function fixTableFieldKeys($field)
  301. {
  302. $this->field = array();
  303. if (!empty($field['name'])) {
  304. $this->field_name = $field['name'];
  305. } else {
  306. $this->field_name = '';
  307. }
  308. if (!empty($field['was'])) {
  309. $this->field['was'] = $field['was'];
  310. }
  311. if (!empty($field['type'])) {
  312. $this->field['type'] = $field['type'];
  313. }
  314. if (!empty($field['fixed'])) {
  315. $this->field['fixed'] = $field['fixed'];
  316. }
  317. if (isset($field['default'])) {
  318. $this->field['default'] = $field['default'];
  319. }
  320. if (!empty($field['notnull'])) {
  321. $this->field['notnull'] = $field['notnull'];
  322. }
  323. if (!empty($field['autoincrement'])) {
  324. $this->field['autoincrement'] = $field['autoincrement'];
  325. }
  326. if (!empty($field['unsigned'])) {
  327. $this->field['unsigned'] = $field['unsigned'];
  328. }
  329. if (!empty($field['length'])) {
  330. $this->field['length'] = $field['length'];
  331. }
  332. if (!empty($field['description'])) {
  333. $this->field['description'] = $field['description'];
  334. }
  335. if (!empty($field['comments'])) {
  336. $this->field['comments'] = $field['comments'];
  337. }
  338. $result = $this->val->validateField($this->table['fields'], $this->field, $this->field_name);
  339. if (PEAR::isError($result)) {
  340. return $this->raiseError($result->getUserinfo());
  341. } else {
  342. $this->table['fields'][$this->field_name] = $this->field;
  343. }
  344. return MDB2_OK;
  345. }
  346. /**
  347. * Enforce the default values for mandatory keys and ensure everything goes
  348. * always in the same order (simulates the behaviour of the original
  349. * parser). Works at table index level.
  350. *
  351. * @param array $index array with table index definition
  352. *
  353. * @return bool|error MDB2_OK on success or error object
  354. *
  355. * @access private
  356. */
  357. function fixTableIndexKeys($index)
  358. {
  359. $this->index = array(
  360. 'was' => '',
  361. 'unique' =>'',
  362. 'primary' => '',
  363. 'fields' => array()
  364. );
  365. if (!empty($index['name'])) {
  366. $this->index_name = $index['name'];
  367. } else {
  368. $this->index_name = '';
  369. }
  370. if (!empty($index['was'])) {
  371. $this->index['was'] = $index['was'];
  372. }
  373. if (!empty($index['unique'])) {
  374. $this->index['unique'] = $index['unique'];
  375. }
  376. if (!empty($index['primary'])) {
  377. $this->index['primary'] = $index['primary'];
  378. }
  379. if (!empty($index['field'])) {
  380. foreach ($index['field'] as $field) {
  381. if (!empty($field['name'])) {
  382. $this->field_name = $field['name'];
  383. } else {
  384. $this->field_name = '';
  385. }
  386. $this->field = array(
  387. 'sorting' => '',
  388. 'length' => ''
  389. );
  390. if (!empty($field['sorting'])) {
  391. $this->field['sorting'] = $field['sorting'];
  392. }
  393. if (!empty($field['length'])) {
  394. $this->field['length'] = $field['length'];
  395. }
  396. $result = $this->val->validateIndexField($this->index['fields'], $this->field, $this->field_name);
  397. if (PEAR::isError($result)) {
  398. return $this->raiseError($result->getUserinfo());
  399. }
  400. $this->index['fields'][$this->field_name] = $this->field;
  401. }
  402. }
  403. $result = $this->val->validateIndex($this->table['indexes'], $this->index, $this->index_name);
  404. if (PEAR::isError($result)) {
  405. return $this->raiseError($result->getUserinfo());
  406. } else {
  407. $this->table['indexes'][$this->index_name] = $this->index;
  408. }
  409. return MDB2_OK;
  410. }
  411. /**
  412. * Enforce the default values for mandatory keys and ensure everything goes
  413. * always in the same order (simulates the behaviour of the original
  414. * parser). Works at table constraint level.
  415. *
  416. * @param array $constraint array with table index definition
  417. *
  418. * @return bool|error MDB2_OK on success or error object
  419. *
  420. * @access private
  421. */
  422. function fixTableConstraintKeys($constraint)
  423. {
  424. $this->constraint = array(
  425. 'was' => '',
  426. 'match' => '',
  427. 'ondelete' => '',
  428. 'onupdate' => '',
  429. 'deferrable' => '',
  430. 'initiallydeferred' => '',
  431. 'foreign' => true,
  432. 'fields' => array(),
  433. 'references' => array('table' => '', 'fields' => array())
  434. );
  435. if (!empty($constraint['name'])) {
  436. $this->constraint_name = $constraint['name'];
  437. } else {
  438. $this->constraint_name = '';
  439. }
  440. if (!empty($constraint['was'])) {
  441. $this->constraint['was'] = $constraint['was'];
  442. }
  443. if (!empty($constraint['match'])) {
  444. $this->constraint['match'] = $constraint['match'];
  445. }
  446. if (!empty($constraint['ondelete'])) {
  447. $this->constraint['ondelete'] = $constraint['ondelete'];
  448. }
  449. if (!empty($constraint['onupdate'])) {
  450. $this->constraint['onupdate'] = $constraint['onupdate'];
  451. }
  452. if (!empty($constraint['deferrable'])) {
  453. $this->constraint['deferrable'] = $constraint['deferrable'];
  454. }
  455. if (!empty($constraint['initiallydeferred'])) {
  456. $this->constraint['initiallydeferred'] = $constraint['initiallydeferred'];
  457. }
  458. if (!empty($constraint['field']) && is_array($constraint['field'])) {
  459. foreach ($constraint['field'] as $field) {
  460. $result = $this->val->validateConstraintField($this->constraint['fields'], $field);
  461. if (PEAR::isError($result)) {
  462. return $this->raiseError($result->getUserinfo());
  463. }
  464. $this->constraint['fields'][$field] = '';
  465. }
  466. }
  467. if (!empty($constraint['references']) && is_array($constraint['references'])) {
  468. /**
  469. * As we forced 'table' to be enumerated
  470. * we have to fix it on the foreign-references-table context
  471. */
  472. if (!empty($constraint['references']['table']) && is_array($constraint['references']['table'])) {
  473. $this->constraint['references']['table'] = $constraint['references']['table'][0];
  474. }
  475. if (!empty($constraint['references']['field']) && is_array($constraint['references']['field'])) {
  476. foreach ($constraint['references']['field'] as $field) {
  477. $result = $this->val->validateConstraintReferencedField($this->constraint['references']['fields'], $field);
  478. if (PEAR::isError($result)) {
  479. return $this->raiseError($result->getUserinfo());
  480. }
  481. $this->constraint['references']['fields'][$field] = '';
  482. }
  483. }
  484. }
  485. $result = $this->val->validateConstraint($this->table['constraints'], $this->constraint, $this->constraint_name);
  486. if (PEAR::isError($result)) {
  487. return $this->raiseError($result->getUserinfo());
  488. } else {
  489. $this->table['constraints'][$this->constraint_name] = $this->constraint;
  490. }
  491. return MDB2_OK;
  492. }
  493. /**
  494. * Enforce the default values for mandatory keys and ensure everything goes
  495. * always in the same order (simulates the behaviour of the original
  496. * parser). Works at table data level.
  497. *
  498. * @param array $element multi dimensional array with query definition
  499. * @param string $type whether its a insert|update|delete query
  500. *
  501. * @return bool|error MDB2_OK on success or error object
  502. *
  503. * @access private
  504. */
  505. function fixTableInitializationKeys($element, $type = '')
  506. {
  507. if (!empty($element['select']) && is_array($element['select'])) {
  508. $this->fixTableInitializationDataKeys($element['select']);
  509. $this->init = array( 'select' => $this->init );
  510. } else {
  511. $this->fixTableInitializationDataKeys($element);
  512. }
  513. $this->table['initialization'][] = array( 'type' => $type, 'data' => $this->init );
  514. }
  515. /**
  516. * Enforce the default values for mandatory keys and ensure everything goes
  517. * always in the same order (simulates the behaviour of the original
  518. * parser). Works deeper at the table initialization level (data). At this
  519. * point we are look at one of the below:
  520. *
  521. * <insert>
  522. * {field}+
  523. * </insert>
  524. *
  525. * <select> (this is a select extracted off a insert-select query)
  526. * <table/>
  527. * {field}+
  528. * <where>
  529. * {expression}
  530. * </where>?
  531. * </select>
  532. *
  533. * <update>
  534. * {field}+
  535. * <where>
  536. * {expression}
  537. * </where>?
  538. * </update>
  539. *
  540. * <delete>
  541. * <where>
  542. * {expression}
  543. * </where>
  544. * </delete>
  545. *
  546. * @param array $element multi dimensional array with query definition
  547. *
  548. * @return bool|error MDB2_OK on success or error object
  549. *
  550. * @access private
  551. */
  552. function fixTableInitializationDataKeys($element)
  553. {
  554. $this->init = array();
  555. if (!empty($element['field']) && is_array($element['field'])) {
  556. foreach ($element['field'] as $field) {
  557. $name = $field['name'];
  558. unset($field['name']);
  559. $this->setExpression($field);
  560. $this->init['field'][] = array( 'name' => $name, 'group' => $field );
  561. }
  562. }
  563. /**
  564. * As we forced 'table' to be enumerated
  565. * we have to fix it on the insert-select context
  566. */
  567. if (!empty($element['table']) && is_array($element['table'])) {
  568. $this->init['table'] = $element['table'][0];
  569. }
  570. if (!empty($element['where']) && is_array($element['where'])) {
  571. $this->init['where'] = $element['where'];
  572. $this->setExpression($this->init['where']);
  573. }
  574. }
  575. /**
  576. * Recursively diggs into an "expression" element. According to our
  577. * documentation an "expression" element is of the kind:
  578. *
  579. * <expression>
  580. * <null/> or <value/> or <column/> or {function} or {expression}
  581. * <operator/>
  582. * <null/> or <value/> or <column/> or {function} or {expression}
  583. * </expression>
  584. *
  585. * @param array &$arr reference to current element definition
  586. *
  587. * @return void
  588. *
  589. * @access private
  590. */
  591. function setExpression(&$arr)
  592. {
  593. $element = each($arr);
  594. $arr = array( 'type' => $element['key'] );
  595. $element = $element['value'];
  596. switch ($arr['type']) {
  597. case 'null':
  598. break;
  599. case 'value':
  600. case 'column':
  601. $arr['data'] = $element;
  602. break;
  603. case 'function':
  604. if (!empty($element)
  605. && is_array($element)
  606. ) {
  607. $arr['data'] = array( 'name' => $element['name'] );
  608. unset($element['name']);
  609. foreach ($element as $type => $value) {
  610. if (!empty($value)) {
  611. if (is_array($value)) {
  612. foreach ($value as $argument) {
  613. $argument = array( $type => $argument );
  614. $this->setExpression($argument);
  615. $arr['data']['arguments'][] = $argument;
  616. }
  617. } else {
  618. $arr['data']['arguments'][] = array( 'type' => $type, 'data' => $value );
  619. }
  620. }
  621. }
  622. }
  623. break;
  624. case 'expression':
  625. $arr['data'] = array( 'operants' => array(), 'operator' => $element['operator'] );
  626. unset($element['operator']);
  627. foreach ($element as $k => $v) {
  628. $argument = array( $k => $v );
  629. $this->setExpression($argument);
  630. $arr['data']['operants'][] = $argument;
  631. }
  632. break;
  633. }
  634. }
  635. /**
  636. * Enforce the default values for mandatory keys and ensure everything goes
  637. * always in the same order (simulates the behaviour of the original
  638. * parser). Works at database sequences level. A "sequence" element looks
  639. * like:
  640. *
  641. * <sequence>
  642. * <name/>
  643. * <was/>?
  644. * <start/>?
  645. * <description/>?
  646. * <comments/>?
  647. * <on>
  648. * <table/>
  649. * <field/>
  650. * </on>?
  651. * </sequence>
  652. *
  653. * @param array $sequence multi dimensional array with sequence definition
  654. *
  655. * @return bool|error MDB2_OK on success or error object
  656. *
  657. * @access private
  658. */
  659. function fixSequenceKeys($sequence)
  660. {
  661. $this->sequence = array(
  662. 'was' => '',
  663. 'start' => '',
  664. 'description' => '',
  665. 'comments' => '',
  666. );
  667. if (!empty($sequence['name'])) {
  668. $this->sequence_name = $sequence['name'];
  669. } else {
  670. $this->sequence_name = '';
  671. }
  672. if (!empty($sequence['was'])) {
  673. $this->sequence['was'] = $sequence['was'];
  674. }
  675. if (!empty($sequence['start'])) {
  676. $this->sequence['start'] = $sequence['start'];
  677. }
  678. if (!empty($sequence['description'])) {
  679. $this->sequence['description'] = $sequence['description'];
  680. }
  681. if (!empty($sequence['comments'])) {
  682. $this->sequence['comments'] = $sequence['comments'];
  683. }
  684. if (!empty($sequence['on']) && is_array($sequence['on'])) {
  685. /**
  686. * As we forced 'table' to be enumerated
  687. * we have to fix it on the sequence-on-table context
  688. */
  689. if (!empty($sequence['on']['table']) && is_array($sequence['on']['table'])) {
  690. $this->sequence['on']['table'] = $sequence['on']['table'][0];
  691. }
  692. /**
  693. * As we forced 'field' to be enumerated
  694. * we have to fix it on the sequence-on-field context
  695. */
  696. if (!empty($sequence['on']['field']) && is_array($sequence['on']['field'])) {
  697. $this->sequence['on']['field'] = $sequence['on']['field'][0];
  698. }
  699. }
  700. $result = $this->val->validateSequence($this->database_definition['sequences'], $this->sequence, $this->sequence_name);
  701. if (PEAR::isError($result)) {
  702. return $this->raiseError($result->getUserinfo());
  703. } else {
  704. $this->database_definition['sequences'][$this->sequence_name] = $this->sequence;
  705. }
  706. return MDB2_OK;
  707. }
  708. /**
  709. * Pushes a MDB2_Schema_Error into stack and returns it
  710. *
  711. * @param string $msg textual message
  712. * @param int $ecode MDB2_Schema's error code
  713. *
  714. * @return object
  715. * @access private
  716. * @static
  717. */
  718. function &raiseError($msg = null, $ecode = MDB2_SCHEMA_ERROR_PARSE)
  719. {
  720. if (is_null($this->error)) {
  721. $error = 'Parser error: '.$msg."\n";
  722. $this->error = MDB2_Schema::raiseError($ecode, null, null, $error);
  723. }
  724. return $this->error;
  725. }
  726. }