adodb-xmlschema.inc.php 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226
  1. <?php
  2. // Copyright (c) 2004 ars Cognita Inc., all rights reserved
  3. /* ******************************************************************************
  4. Released under both BSD license and Lesser GPL library license.
  5. Whenever there is any discrepancy between the two licenses,
  6. the BSD license will take precedence.
  7. *******************************************************************************/
  8. /**
  9. * xmlschema is a class that allows the user to quickly and easily
  10. * build a database on any ADOdb-supported platform using a simple
  11. * XML schema.
  12. *
  13. * Last Editor: $Author: jlim $
  14. * @author Richard Tango-Lowy & Dan Cech
  15. * @version $Revision: 1.12 $
  16. *
  17. * @package axmls
  18. * @tutorial getting_started.pkg
  19. */
  20. function _file_get_contents($file)
  21. {
  22. if (function_exists('file_get_contents')) return file_get_contents($file);
  23. $f = fopen($file,'r');
  24. if (!$f) return '';
  25. $t = '';
  26. while ($s = fread($f,100000)) $t .= $s;
  27. fclose($f);
  28. return $t;
  29. }
  30. /**
  31. * Debug on or off
  32. */
  33. if( !defined( 'XMLS_DEBUG' ) ) {
  34. define( 'XMLS_DEBUG', FALSE );
  35. }
  36. /**
  37. * Default prefix key
  38. */
  39. if( !defined( 'XMLS_PREFIX' ) ) {
  40. define( 'XMLS_PREFIX', '%%P' );
  41. }
  42. /**
  43. * Maximum length allowed for object prefix
  44. */
  45. if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
  46. define( 'XMLS_PREFIX_MAXLEN', 10 );
  47. }
  48. /**
  49. * Execute SQL inline as it is generated
  50. */
  51. if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
  52. define( 'XMLS_EXECUTE_INLINE', FALSE );
  53. }
  54. /**
  55. * Continue SQL Execution if an error occurs?
  56. */
  57. if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
  58. define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
  59. }
  60. /**
  61. * Current Schema Version
  62. */
  63. if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
  64. define( 'XMLS_SCHEMA_VERSION', '0.2' );
  65. }
  66. /**
  67. * Default Schema Version. Used for Schemas without an explicit version set.
  68. */
  69. if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
  70. define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
  71. }
  72. /**
  73. * Default Schema Version. Used for Schemas without an explicit version set.
  74. */
  75. if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
  76. define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
  77. }
  78. /**
  79. * Include the main ADODB library
  80. */
  81. if( !defined( '_ADODB_LAYER' ) ) {
  82. require( 'adodb.inc.php' );
  83. require( 'adodb-datadict.inc.php' );
  84. }
  85. /**
  86. * Abstract DB Object. This class provides basic methods for database objects, such
  87. * as tables and indexes.
  88. *
  89. * @package axmls
  90. * @access private
  91. */
  92. class dbObject {
  93. /**
  94. * var object Parent
  95. */
  96. var $parent;
  97. /**
  98. * var string current element
  99. */
  100. var $currentElement;
  101. /**
  102. * NOP
  103. */
  104. function __construct( &$parent, $attributes = NULL ) {
  105. $this->parent = $parent;
  106. }
  107. /**
  108. * XML Callback to process start elements
  109. *
  110. * @access private
  111. */
  112. function _tag_open( &$parser, $tag, $attributes ) {
  113. }
  114. /**
  115. * XML Callback to process CDATA elements
  116. *
  117. * @access private
  118. */
  119. function _tag_cdata( &$parser, $cdata ) {
  120. }
  121. /**
  122. * XML Callback to process end elements
  123. *
  124. * @access private
  125. */
  126. function _tag_close( &$parser, $tag ) {
  127. }
  128. function create(&$xmls) {
  129. return array();
  130. }
  131. /**
  132. * Destroys the object
  133. */
  134. function destroy() {
  135. }
  136. /**
  137. * Checks whether the specified RDBMS is supported by the current
  138. * database object or its ranking ancestor.
  139. *
  140. * @param string $platform RDBMS platform name (from ADODB platform list).
  141. * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
  142. */
  143. function supportedPlatform( $platform = NULL ) {
  144. return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
  145. }
  146. /**
  147. * Returns the prefix set by the ranking ancestor of the database object.
  148. *
  149. * @param string $name Prefix string.
  150. * @return string Prefix.
  151. */
  152. function prefix( $name = '' ) {
  153. return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
  154. }
  155. /**
  156. * Extracts a field ID from the specified field.
  157. *
  158. * @param string $field Field.
  159. * @return string Field ID.
  160. */
  161. function FieldID( $field ) {
  162. return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
  163. }
  164. }
  165. /**
  166. * Creates a table object in ADOdb's datadict format
  167. *
  168. * This class stores information about a database table. As charactaristics
  169. * of the table are loaded from the external source, methods and properties
  170. * of this class are used to build up the table description in ADOdb's
  171. * datadict format.
  172. *
  173. * @package axmls
  174. * @access private
  175. */
  176. class dbTable extends dbObject {
  177. /**
  178. * @var string Table name
  179. */
  180. var $name;
  181. /**
  182. * @var array Field specifier: Meta-information about each field
  183. */
  184. var $fields = array();
  185. /**
  186. * @var array List of table indexes.
  187. */
  188. var $indexes = array();
  189. /**
  190. * @var array Table options: Table-level options
  191. */
  192. var $opts = array();
  193. /**
  194. * @var string Field index: Keeps track of which field is currently being processed
  195. */
  196. var $current_field;
  197. /**
  198. * @var boolean Mark table for destruction
  199. * @access private
  200. */
  201. var $drop_table;
  202. /**
  203. * @var boolean Mark field for destruction (not yet implemented)
  204. * @access private
  205. */
  206. var $drop_field = array();
  207. /**
  208. * Iniitializes a new table object.
  209. *
  210. * @param string $prefix DB Object prefix
  211. * @param array $attributes Array of table attributes.
  212. */
  213. function __construct( &$parent, $attributes = NULL ) {
  214. $this->parent = $parent;
  215. $this->name = $this->prefix($attributes['NAME']);
  216. }
  217. /**
  218. * XML Callback to process start elements. Elements currently
  219. * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT.
  220. *
  221. * @access private
  222. */
  223. function _tag_open( &$parser, $tag, $attributes ) {
  224. $this->currentElement = strtoupper( $tag );
  225. switch( $this->currentElement ) {
  226. case 'INDEX':
  227. if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
  228. $index = $this->addIndex( $attributes );
  229. xml_set_object( $parser, $index );
  230. }
  231. break;
  232. case 'DATA':
  233. if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
  234. $data = $this->addData( $attributes );
  235. xml_set_object( $parser, $data );
  236. }
  237. break;
  238. case 'DROP':
  239. $this->drop();
  240. break;
  241. case 'FIELD':
  242. // Add a field
  243. $fieldName = $attributes['NAME'];
  244. $fieldType = $attributes['TYPE'];
  245. $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
  246. $fieldOpts = isset( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
  247. $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
  248. break;
  249. case 'KEY':
  250. case 'NOTNULL':
  251. case 'AUTOINCREMENT':
  252. // Add a field option
  253. $this->addFieldOpt( $this->current_field, $this->currentElement );
  254. break;
  255. case 'DEFAULT':
  256. // Add a field option to the table object
  257. // Work around ADOdb datadict issue that misinterprets empty strings.
  258. if( $attributes['VALUE'] == '' ) {
  259. $attributes['VALUE'] = " '' ";
  260. }
  261. $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
  262. break;
  263. case 'DEFDATE':
  264. case 'DEFTIMESTAMP':
  265. // Add a field option to the table object
  266. $this->addFieldOpt( $this->current_field, $this->currentElement );
  267. break;
  268. default:
  269. // print_r( array( $tag, $attributes ) );
  270. }
  271. }
  272. /**
  273. * XML Callback to process CDATA elements
  274. *
  275. * @access private
  276. */
  277. function _tag_cdata( &$parser, $cdata ) {
  278. switch( $this->currentElement ) {
  279. // Table constraint
  280. case 'CONSTRAINT':
  281. if( isset( $this->current_field ) ) {
  282. $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
  283. } else {
  284. $this->addTableOpt( $cdata );
  285. }
  286. break;
  287. // Table option
  288. case 'OPT':
  289. $this->addTableOpt( $cdata );
  290. break;
  291. default:
  292. }
  293. }
  294. /**
  295. * XML Callback to process end elements
  296. *
  297. * @access private
  298. */
  299. function _tag_close( &$parser, $tag ) {
  300. $this->currentElement = '';
  301. switch( strtoupper( $tag ) ) {
  302. case 'TABLE':
  303. $this->parent->addSQL( $this->create( $this->parent ) );
  304. xml_set_object( $parser, $this->parent );
  305. $this->destroy();
  306. break;
  307. case 'FIELD':
  308. unset($this->current_field);
  309. break;
  310. }
  311. }
  312. /**
  313. * Adds an index to a table object
  314. *
  315. * @param array $attributes Index attributes
  316. * @return object dbIndex object
  317. */
  318. function addIndex( $attributes ) {
  319. $name = strtoupper( $attributes['NAME'] );
  320. $this->indexes[$name] = new dbIndex( $this, $attributes );
  321. return $this->indexes[$name];
  322. }
  323. /**
  324. * Adds data to a table object
  325. *
  326. * @param array $attributes Data attributes
  327. * @return object dbData object
  328. */
  329. function addData( $attributes ) {
  330. if( !isset( $this->data ) ) {
  331. $this->data = new dbData( $this, $attributes );
  332. }
  333. return $this->data;
  334. }
  335. /**
  336. * Adds a field to a table object
  337. *
  338. * $name is the name of the table to which the field should be added.
  339. * $type is an ADODB datadict field type. The following field types
  340. * are supported as of ADODB 3.40:
  341. * - C: varchar
  342. * - X: CLOB (character large object) or largest varchar size
  343. * if CLOB is not supported
  344. * - C2: Multibyte varchar
  345. * - X2: Multibyte CLOB
  346. * - B: BLOB (binary large object)
  347. * - D: Date (some databases do not support this, and we return a datetime type)
  348. * - T: Datetime or Timestamp
  349. * - L: Integer field suitable for storing booleans (0 or 1)
  350. * - I: Integer (mapped to I4)
  351. * - I1: 1-byte integer
  352. * - I2: 2-byte integer
  353. * - I4: 4-byte integer
  354. * - I8: 8-byte integer
  355. * - F: Floating point number
  356. * - N: Numeric or decimal number
  357. *
  358. * @param string $name Name of the table to which the field will be added.
  359. * @param string $type ADODB datadict field type.
  360. * @param string $size Field size
  361. * @param array $opts Field options array
  362. * @return array Field specifier array
  363. */
  364. function addField( $name, $type, $size = NULL, $opts = NULL ) {
  365. $field_id = $this->FieldID( $name );
  366. // Set the field index so we know where we are
  367. $this->current_field = $field_id;
  368. // Set the field name (required)
  369. $this->fields[$field_id]['NAME'] = $name;
  370. // Set the field type (required)
  371. $this->fields[$field_id]['TYPE'] = $type;
  372. // Set the field size (optional)
  373. if( isset( $size ) ) {
  374. $this->fields[$field_id]['SIZE'] = $size;
  375. }
  376. // Set the field options
  377. if( isset( $opts ) ) {
  378. $this->fields[$field_id]['OPTS'][] = $opts;
  379. }
  380. }
  381. /**
  382. * Adds a field option to the current field specifier
  383. *
  384. * This method adds a field option allowed by the ADOdb datadict
  385. * and appends it to the given field.
  386. *
  387. * @param string $field Field name
  388. * @param string $opt ADOdb field option
  389. * @param mixed $value Field option value
  390. * @return array Field specifier array
  391. */
  392. function addFieldOpt( $field, $opt, $value = NULL ) {
  393. if( !isset( $value ) ) {
  394. $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
  395. // Add the option and value
  396. } else {
  397. $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
  398. }
  399. }
  400. /**
  401. * Adds an option to the table
  402. *
  403. * This method takes a comma-separated list of table-level options
  404. * and appends them to the table object.
  405. *
  406. * @param string $opt Table option
  407. * @return array Options
  408. */
  409. function addTableOpt( $opt ) {
  410. if(isset($this->currentPlatform)) {
  411. $this->opts[$this->parent->db->databaseType] = $opt;
  412. }
  413. return $this->opts;
  414. }
  415. /**
  416. * Generates the SQL that will create the table in the database
  417. *
  418. * @param object $xmls adoSchema object
  419. * @return array Array containing table creation SQL
  420. */
  421. function create( &$xmls ) {
  422. $sql = array();
  423. // drop any existing indexes
  424. if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
  425. foreach( $legacy_indexes as $index => $index_details ) {
  426. $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
  427. }
  428. }
  429. // remove fields to be dropped from table object
  430. foreach( $this->drop_field as $field ) {
  431. unset( $this->fields[$field] );
  432. }
  433. // if table exists
  434. if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
  435. // drop table
  436. if( $this->drop_table ) {
  437. $sql[] = $xmls->dict->DropTableSQL( $this->name );
  438. return $sql;
  439. }
  440. // drop any existing fields not in schema
  441. foreach( $legacy_fields as $field_id => $field ) {
  442. if( !isset( $this->fields[$field_id] ) ) {
  443. $sql[] = $xmls->dict->DropColumnSQL( $this->name, '`'.$field->name.'`' );
  444. }
  445. }
  446. // if table doesn't exist
  447. } else {
  448. if( $this->drop_table ) {
  449. return $sql;
  450. }
  451. $legacy_fields = array();
  452. }
  453. // Loop through the field specifier array, building the associative array for the field options
  454. $fldarray = array();
  455. foreach( $this->fields as $field_id => $finfo ) {
  456. // Set an empty size if it isn't supplied
  457. if( !isset( $finfo['SIZE'] ) ) {
  458. $finfo['SIZE'] = '';
  459. }
  460. // Initialize the field array with the type and size
  461. $fldarray[$field_id] = array(
  462. 'NAME' => $finfo['NAME'],
  463. 'TYPE' => $finfo['TYPE'],
  464. 'SIZE' => $finfo['SIZE']
  465. );
  466. // Loop through the options array and add the field options.
  467. if( isset( $finfo['OPTS'] ) ) {
  468. foreach( $finfo['OPTS'] as $opt ) {
  469. // Option has an argument.
  470. if( is_array( $opt ) ) {
  471. $key = key( $opt );
  472. $value = $opt[key( $opt )];
  473. @$fldarray[$field_id][$key] .= $value;
  474. // Option doesn't have arguments
  475. } else {
  476. $fldarray[$field_id][$opt] = $opt;
  477. }
  478. }
  479. }
  480. }
  481. if( empty( $legacy_fields ) ) {
  482. // Create the new table
  483. $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
  484. logMsg( end( $sql ), 'Generated CreateTableSQL' );
  485. } else {
  486. // Upgrade an existing table
  487. logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
  488. switch( $xmls->upgrade ) {
  489. // Use ChangeTableSQL
  490. case 'ALTER':
  491. logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
  492. $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
  493. break;
  494. case 'REPLACE':
  495. logMsg( 'Doing upgrade REPLACE (testing)' );
  496. $sql[] = $xmls->dict->DropTableSQL( $this->name );
  497. $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
  498. break;
  499. // ignore table
  500. default:
  501. return array();
  502. }
  503. }
  504. foreach( $this->indexes as $index ) {
  505. $sql[] = $index->create( $xmls );
  506. }
  507. if( isset( $this->data ) ) {
  508. $sql[] = $this->data->create( $xmls );
  509. }
  510. return $sql;
  511. }
  512. /**
  513. * Marks a field or table for destruction
  514. */
  515. function drop() {
  516. if( isset( $this->current_field ) ) {
  517. // Drop the current field
  518. logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
  519. // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
  520. $this->drop_field[$this->current_field] = $this->current_field;
  521. } else {
  522. // Drop the current table
  523. logMsg( "Dropping table '{$this->name}'" );
  524. // $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
  525. $this->drop_table = TRUE;
  526. }
  527. }
  528. }
  529. /**
  530. * Creates an index object in ADOdb's datadict format
  531. *
  532. * This class stores information about a database index. As charactaristics
  533. * of the index are loaded from the external source, methods and properties
  534. * of this class are used to build up the index description in ADOdb's
  535. * datadict format.
  536. *
  537. * @package axmls
  538. * @access private
  539. */
  540. class dbIndex extends dbObject {
  541. /**
  542. * @var string Index name
  543. */
  544. var $name;
  545. /**
  546. * @var array Index options: Index-level options
  547. */
  548. var $opts = array();
  549. /**
  550. * @var array Indexed fields: Table columns included in this index
  551. */
  552. var $columns = array();
  553. /**
  554. * @var boolean Mark index for destruction
  555. * @access private
  556. */
  557. var $drop = FALSE;
  558. /**
  559. * Initializes the new dbIndex object.
  560. *
  561. * @param object $parent Parent object
  562. * @param array $attributes Attributes
  563. *
  564. * @internal
  565. */
  566. function __construct( &$parent, $attributes = NULL ) {
  567. $this->parent = $parent;
  568. $this->name = $this->prefix ($attributes['NAME']);
  569. }
  570. /**
  571. * XML Callback to process start elements
  572. *
  573. * Processes XML opening tags.
  574. * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
  575. *
  576. * @access private
  577. */
  578. function _tag_open( &$parser, $tag, $attributes ) {
  579. $this->currentElement = strtoupper( $tag );
  580. switch( $this->currentElement ) {
  581. case 'DROP':
  582. $this->drop();
  583. break;
  584. case 'CLUSTERED':
  585. case 'BITMAP':
  586. case 'UNIQUE':
  587. case 'FULLTEXT':
  588. case 'HASH':
  589. // Add index Option
  590. $this->addIndexOpt( $this->currentElement );
  591. break;
  592. default:
  593. // print_r( array( $tag, $attributes ) );
  594. }
  595. }
  596. /**
  597. * XML Callback to process CDATA elements
  598. *
  599. * Processes XML cdata.
  600. *
  601. * @access private
  602. */
  603. function _tag_cdata( &$parser, $cdata ) {
  604. switch( $this->currentElement ) {
  605. // Index field name
  606. case 'COL':
  607. $this->addField( $cdata );
  608. break;
  609. default:
  610. }
  611. }
  612. /**
  613. * XML Callback to process end elements
  614. *
  615. * @access private
  616. */
  617. function _tag_close( &$parser, $tag ) {
  618. $this->currentElement = '';
  619. switch( strtoupper( $tag ) ) {
  620. case 'INDEX':
  621. xml_set_object( $parser, $this->parent );
  622. break;
  623. }
  624. }
  625. /**
  626. * Adds a field to the index
  627. *
  628. * @param string $name Field name
  629. * @return string Field list
  630. */
  631. function addField( $name ) {
  632. $this->columns[$this->FieldID( $name )] = $name;
  633. // Return the field list
  634. return $this->columns;
  635. }
  636. /**
  637. * Adds options to the index
  638. *
  639. * @param string $opt Comma-separated list of index options.
  640. * @return string Option list
  641. */
  642. function addIndexOpt( $opt ) {
  643. $this->opts[] = $opt;
  644. // Return the options list
  645. return $this->opts;
  646. }
  647. /**
  648. * Generates the SQL that will create the index in the database
  649. *
  650. * @param object $xmls adoSchema object
  651. * @return array Array containing index creation SQL
  652. */
  653. function create( &$xmls ) {
  654. if( $this->drop ) {
  655. return NULL;
  656. }
  657. // eliminate any columns that aren't in the table
  658. foreach( $this->columns as $id => $col ) {
  659. if( !isset( $this->parent->fields[$id] ) ) {
  660. unset( $this->columns[$id] );
  661. }
  662. }
  663. return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
  664. }
  665. /**
  666. * Marks an index for destruction
  667. */
  668. function drop() {
  669. $this->drop = TRUE;
  670. }
  671. }
  672. /**
  673. * Creates a data object in ADOdb's datadict format
  674. *
  675. * This class stores information about table data.
  676. *
  677. * @package axmls
  678. * @access private
  679. */
  680. class dbData extends dbObject {
  681. var $data = array();
  682. var $row;
  683. /**
  684. * Initializes the new dbIndex object.
  685. *
  686. * @param object $parent Parent object
  687. * @param array $attributes Attributes
  688. *
  689. * @internal
  690. */
  691. function __construct( &$parent, $attributes = NULL ) {
  692. $this->parent = $parent;
  693. }
  694. /**
  695. * XML Callback to process start elements
  696. *
  697. * Processes XML opening tags.
  698. * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
  699. *
  700. * @access private
  701. */
  702. function _tag_open( &$parser, $tag, $attributes ) {
  703. $this->currentElement = strtoupper( $tag );
  704. switch( $this->currentElement ) {
  705. case 'ROW':
  706. $this->row = count( $this->data );
  707. $this->data[$this->row] = array();
  708. break;
  709. case 'F':
  710. $this->addField($attributes);
  711. default:
  712. // print_r( array( $tag, $attributes ) );
  713. }
  714. }
  715. /**
  716. * XML Callback to process CDATA elements
  717. *
  718. * Processes XML cdata.
  719. *
  720. * @access private
  721. */
  722. function _tag_cdata( &$parser, $cdata ) {
  723. switch( $this->currentElement ) {
  724. // Index field name
  725. case 'F':
  726. $this->addData( $cdata );
  727. break;
  728. default:
  729. }
  730. }
  731. /**
  732. * XML Callback to process end elements
  733. *
  734. * @access private
  735. */
  736. function _tag_close( &$parser, $tag ) {
  737. $this->currentElement = '';
  738. switch( strtoupper( $tag ) ) {
  739. case 'DATA':
  740. xml_set_object( $parser, $this->parent );
  741. break;
  742. }
  743. }
  744. /**
  745. * Adds a field to the index
  746. *
  747. * @param string $name Field name
  748. * @return string Field list
  749. */
  750. function addField( $attributes ) {
  751. if( isset( $attributes['NAME'] ) ) {
  752. $name = $attributes['NAME'];
  753. } else {
  754. $name = count($this->data[$this->row]);
  755. }
  756. // Set the field index so we know where we are
  757. $this->current_field = $this->FieldID( $name );
  758. }
  759. /**
  760. * Adds options to the index
  761. *
  762. * @param string $opt Comma-separated list of index options.
  763. * @return string Option list
  764. */
  765. function addData( $cdata ) {
  766. if( !isset( $this->data[$this->row] ) ) {
  767. $this->data[$this->row] = array();
  768. }
  769. if( !isset( $this->data[$this->row][$this->current_field] ) ) {
  770. $this->data[$this->row][$this->current_field] = '';
  771. }
  772. $this->data[$this->row][$this->current_field] .= $cdata;
  773. }
  774. /**
  775. * Generates the SQL that will create the index in the database
  776. *
  777. * @param object $xmls adoSchema object
  778. * @return array Array containing index creation SQL
  779. */
  780. function create( &$xmls ) {
  781. $table = $xmls->dict->TableName($this->parent->name);
  782. $table_field_count = count($this->parent->fields);
  783. $sql = array();
  784. // eliminate any columns that aren't in the table
  785. foreach( $this->data as $row ) {
  786. $table_fields = $this->parent->fields;
  787. $fields = array();
  788. foreach( $row as $field_id => $field_data ) {
  789. if( !array_key_exists( $field_id, $table_fields ) ) {
  790. if( is_numeric( $field_id ) ) {
  791. $field_id = reset( array_keys( $table_fields ) );
  792. } else {
  793. continue;
  794. }
  795. }
  796. $name = $table_fields[$field_id]['NAME'];
  797. switch( $table_fields[$field_id]['TYPE'] ) {
  798. case 'C':
  799. case 'C2':
  800. case 'X':
  801. case 'X2':
  802. $fields[$name] = $xmls->db->qstr( $field_data );
  803. break;
  804. case 'I':
  805. case 'I1':
  806. case 'I2':
  807. case 'I4':
  808. case 'I8':
  809. $fields[$name] = intval($field_data);
  810. break;
  811. default:
  812. $fields[$name] = $field_data;
  813. }
  814. unset($table_fields[$field_id]);
  815. }
  816. // check that at least 1 column is specified
  817. if( empty( $fields ) ) {
  818. continue;
  819. }
  820. // check that no required columns are missing
  821. if( count( $fields ) < $table_field_count ) {
  822. foreach( $table_fields as $field ) {
  823. if (isset( $field['OPTS'] ))
  824. if( ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
  825. continue(2);
  826. }
  827. }
  828. }
  829. $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
  830. }
  831. return $sql;
  832. }
  833. }
  834. /**
  835. * Creates the SQL to execute a list of provided SQL queries
  836. *
  837. * @package axmls
  838. * @access private
  839. */
  840. class dbQuerySet extends dbObject {
  841. /**
  842. * @var array List of SQL queries
  843. */
  844. var $queries = array();
  845. /**
  846. * @var string String used to build of a query line by line
  847. */
  848. var $query;
  849. /**
  850. * @var string Query prefix key
  851. */
  852. var $prefixKey = '';
  853. /**
  854. * @var boolean Auto prefix enable (TRUE)
  855. */
  856. var $prefixMethod = 'AUTO';
  857. /**
  858. * Initializes the query set.
  859. *
  860. * @param object $parent Parent object
  861. * @param array $attributes Attributes
  862. */
  863. function __construct( &$parent, $attributes = NULL ) {
  864. $this->parent = $parent;
  865. // Overrides the manual prefix key
  866. if( isset( $attributes['KEY'] ) ) {
  867. $this->prefixKey = $attributes['KEY'];
  868. }
  869. $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
  870. // Enables or disables automatic prefix prepending
  871. switch( $prefixMethod ) {
  872. case 'AUTO':
  873. $this->prefixMethod = 'AUTO';
  874. break;
  875. case 'MANUAL':
  876. $this->prefixMethod = 'MANUAL';
  877. break;
  878. case 'NONE':
  879. $this->prefixMethod = 'NONE';
  880. break;
  881. }
  882. }
  883. /**
  884. * XML Callback to process start elements. Elements currently
  885. * processed are: QUERY.
  886. *
  887. * @access private
  888. */
  889. function _tag_open( &$parser, $tag, $attributes ) {
  890. $this->currentElement = strtoupper( $tag );
  891. switch( $this->currentElement ) {
  892. case 'QUERY':
  893. // Create a new query in a SQL queryset.
  894. // Ignore this query set if a platform is specified and it's different than the
  895. // current connection platform.
  896. if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
  897. $this->newQuery();
  898. } else {
  899. $this->discardQuery();
  900. }
  901. break;
  902. default:
  903. // print_r( array( $tag, $attributes ) );
  904. }
  905. }
  906. /**
  907. * XML Callback to process CDATA elements
  908. */
  909. function _tag_cdata( &$parser, $cdata ) {
  910. switch( $this->currentElement ) {
  911. // Line of queryset SQL data
  912. case 'QUERY':
  913. $this->buildQuery( $cdata );
  914. break;
  915. default:
  916. }
  917. }
  918. /**
  919. * XML Callback to process end elements
  920. *
  921. * @access private
  922. */
  923. function _tag_close( &$parser, $tag ) {
  924. $this->currentElement = '';
  925. switch( strtoupper( $tag ) ) {
  926. case 'QUERY':
  927. // Add the finished query to the open query set.
  928. $this->addQuery();
  929. break;
  930. case 'SQL':
  931. $this->parent->addSQL( $this->create( $this->parent ) );
  932. xml_set_object( $parser, $this->parent );
  933. $this->destroy();
  934. break;
  935. default:
  936. }
  937. }
  938. /**
  939. * Re-initializes the query.
  940. *
  941. * @return boolean TRUE
  942. */
  943. function newQuery() {
  944. $this->query = '';
  945. return TRUE;
  946. }
  947. /**
  948. * Discards the existing query.
  949. *
  950. * @return boolean TRUE
  951. */
  952. function discardQuery() {
  953. unset( $this->query );
  954. return TRUE;
  955. }
  956. /**
  957. * Appends a line to a query that is being built line by line
  958. *
  959. * @param string $data Line of SQL data or NULL to initialize a new query
  960. * @return string SQL query string.
  961. */
  962. function buildQuery( $sql = NULL ) {
  963. if( !isset( $this->query ) OR empty( $sql ) ) {
  964. return FALSE;
  965. }
  966. $this->query .= $sql;
  967. return $this->query;
  968. }
  969. /**
  970. * Adds a completed query to the query list
  971. *
  972. * @return string SQL of added query
  973. */
  974. function addQuery() {
  975. if( !isset( $this->query ) ) {
  976. return FALSE;
  977. }
  978. $this->queries[] = $return = trim($this->query);
  979. unset( $this->query );
  980. return $return;
  981. }
  982. /**
  983. * Creates and returns the current query set
  984. *
  985. * @param object $xmls adoSchema object
  986. * @return array Query set
  987. */
  988. function create( &$xmls ) {
  989. foreach( $this->queries as $id => $query ) {
  990. switch( $this->prefixMethod ) {
  991. case 'AUTO':
  992. // Enable auto prefix replacement
  993. // Process object prefix.
  994. // Evaluate SQL statements to prepend prefix to objects
  995. $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
  996. $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
  997. $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
  998. // SELECT statements aren't working yet
  999. #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
  1000. case 'MANUAL':
  1001. // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
  1002. // If prefixKey is not set, we use the default constant XMLS_PREFIX
  1003. if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
  1004. // Enable prefix override
  1005. $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
  1006. } else {
  1007. // Use default replacement
  1008. $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
  1009. }
  1010. }
  1011. $this->queries[$id] = trim( $query );
  1012. }
  1013. // Return the query set array
  1014. return $this->queries;
  1015. }
  1016. /**
  1017. * Rebuilds the query with the prefix attached to any objects
  1018. *
  1019. * @param string $regex Regex used to add prefix
  1020. * @param string $query SQL query string
  1021. * @param string $prefix Prefix to be appended to tables, indices, etc.
  1022. * @return string Prefixed SQL query string.
  1023. */
  1024. function prefixQuery( $regex, $query, $prefix = NULL ) {
  1025. if( !isset( $prefix ) ) {
  1026. return $query;
  1027. }
  1028. if( preg_match( $regex, $query, $match ) ) {
  1029. $preamble = $match[1];
  1030. $postamble = $match[5];
  1031. $objectList = explode( ',', $match[3] );
  1032. // $prefix = $prefix . '_';
  1033. $prefixedList = '';
  1034. foreach( $objectList as $object ) {
  1035. if( $prefixedList !== '' ) {
  1036. $prefixedList .= ', ';
  1037. }
  1038. $prefixedList .= $prefix . trim( $object );
  1039. }
  1040. $query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
  1041. }
  1042. return $query;
  1043. }
  1044. }
  1045. /**
  1046. * Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
  1047. *
  1048. * This class is used to load and parse the XML file, to create an array of SQL statements
  1049. * that can be used to build a database, and to build the database using the SQL array.
  1050. *
  1051. * @tutorial getting_started.pkg
  1052. *
  1053. * @author Richard Tango-Lowy & Dan Cech
  1054. * @version $Revision: 1.12 $
  1055. *
  1056. * @package axmls
  1057. */
  1058. class adoSchema {
  1059. /**
  1060. * @var array Array containing SQL queries to generate all objects
  1061. * @access private
  1062. */
  1063. var $sqlArray;
  1064. /**
  1065. * @var object ADOdb connection object
  1066. * @access private
  1067. */
  1068. var $db;
  1069. /**
  1070. * @var object ADOdb Data Dictionary
  1071. * @access private
  1072. */
  1073. var $dict;
  1074. /**
  1075. * @var string Current XML element
  1076. * @access private
  1077. */
  1078. var $currentElement = '';
  1079. /**
  1080. * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
  1081. * @access private
  1082. */
  1083. var $upgrade = '';
  1084. /**
  1085. * @var string Optional object prefix
  1086. * @access private
  1087. */
  1088. var $objectPrefix = '';
  1089. /**
  1090. * @var long Original Magic Quotes Runtime value
  1091. * @access private
  1092. */
  1093. var $mgq;
  1094. /**
  1095. * @var long System debug
  1096. * @access private
  1097. */
  1098. var $debug;
  1099. /**
  1100. * @var string Regular expression to find schema version
  1101. * @access private
  1102. */
  1103. var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
  1104. /**
  1105. * @var string Current schema version
  1106. * @access private
  1107. */
  1108. var $schemaVersion;
  1109. /**
  1110. * @var int Success of last Schema execution
  1111. */
  1112. var $success;
  1113. /**
  1114. * @var bool Execute SQL inline as it is generated
  1115. */
  1116. var $executeInline;
  1117. /**
  1118. * @var bool Continue SQL execution if errors occur
  1119. */
  1120. var $continueOnError;
  1121. /**
  1122. * Creates an adoSchema object
  1123. *
  1124. * Creating an adoSchema object is the first step in processing an XML schema.
  1125. * The only parameter is an ADOdb database connection object, which must already
  1126. * have been created.
  1127. *
  1128. * @param object $db ADOdb database connection object.
  1129. */
  1130. function __construct( $db ) {
  1131. // Initialize the environment
  1132. $this->mgq = get_magic_quotes_runtime();
  1133. if ($this->mgq !== false) {
  1134. ini_set('magic_quotes_runtime', 0);
  1135. }
  1136. $this->db = $db;
  1137. $this->debug = $this->db->debug;
  1138. $this->dict = NewDataDictionary( $this->db );
  1139. $this->sqlArray = array();
  1140. $this->schemaVersion = XMLS_SCHEMA_VERSION;
  1141. $this->executeInline( XMLS_EXECUTE_INLINE );
  1142. $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
  1143. $this->setUpgradeMethod();
  1144. }
  1145. /**
  1146. * Sets the method to be used for upgrading an existing database
  1147. *
  1148. * Use this method to specify how existing database objects should be upgraded.
  1149. * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
  1150. * alter each database object directly, REPLACE attempts to rebuild each object
  1151. * from scratch, BEST attempts to determine the best upgrade method for each
  1152. * object, and NONE disables upgrading.
  1153. *
  1154. * This method is not yet used by AXMLS, but exists for backward compatibility.
  1155. * The ALTER method is automatically assumed when the adoSchema object is
  1156. * instantiated; other upgrade methods are not currently supported.
  1157. *
  1158. * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
  1159. * @returns string Upgrade method used
  1160. */
  1161. function SetUpgradeMethod( $method = '' ) {
  1162. if( !is_string( $method ) ) {
  1163. return FALSE;
  1164. }
  1165. $method = strtoupper( $method );
  1166. // Handle the upgrade methods
  1167. switch( $method ) {
  1168. case 'ALTER':
  1169. $this->upgrade = $method;
  1170. break;
  1171. case 'REPLACE':
  1172. $this->upgrade = $method;
  1173. break;
  1174. case 'BEST':
  1175. $this->upgrade = 'ALTER';
  1176. break;
  1177. case 'NONE':
  1178. $this->upgrade = 'NONE';
  1179. break;
  1180. default:
  1181. // Use default if no legitimate method is passed.
  1182. $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
  1183. }
  1184. return $this->upgrade;
  1185. }
  1186. /**
  1187. * Enables/disables inline SQL execution.
  1188. *
  1189. * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
  1190. * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
  1191. * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
  1192. * to apply the schema to the database.
  1193. *
  1194. * @param bool $mode execute
  1195. * @return bool current execution mode
  1196. *
  1197. * @see ParseSchema(), ExecuteSchema()
  1198. */
  1199. function ExecuteInline( $mode = NULL ) {
  1200. if( is_bool( $mode ) ) {
  1201. $this->executeInline = $mode;
  1202. }
  1203. return $this->executeInline;
  1204. }
  1205. /**
  1206. * Enables/disables SQL continue on error.
  1207. *
  1208. * Call this method to enable or disable continuation of SQL execution if an error occurs.
  1209. * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
  1210. * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
  1211. * of the schema will continue.
  1212. *
  1213. * @param bool $mode execute
  1214. * @return bool current continueOnError mode
  1215. *
  1216. * @see addSQL(), ExecuteSchema()
  1217. */
  1218. function ContinueOnError( $mode = NULL ) {
  1219. if( is_bool( $mode ) ) {
  1220. $this->continueOnError = $mode;
  1221. }
  1222. return $this->continueOnError;
  1223. }
  1224. /**
  1225. * Loads an XML schema from a file and converts it to SQL.
  1226. *
  1227. * Call this method to load the specified schema (see the DTD for the proper format) from
  1228. * the filesystem and generate the SQL necessary to create the database described.
  1229. * @see ParseSchemaString()
  1230. *
  1231. * @param string $file Name of XML schema file.
  1232. * @param bool $returnSchema Return schema rather than parsing.
  1233. * @return array Array of SQL queries, ready to execute
  1234. */
  1235. function ParseSchema( $filename, $returnSchema = FALSE ) {
  1236. return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
  1237. }
  1238. /**
  1239. * Loads an XML schema from a file and converts it to SQL.
  1240. *
  1241. * Call this method to load the specified schema from a file (see the DTD for the proper format)
  1242. * and generate the SQL necessary to create the database described by the schema.
  1243. *
  1244. * @param string $file Name of XML schema file.
  1245. * @param bool $returnSchema Return schema rather than parsing.
  1246. * @return array Array of SQL queries, ready to execute.
  1247. *
  1248. * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString()
  1249. * @see ParseSchema(), ParseSchemaString()
  1250. */
  1251. function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
  1252. // Open the file
  1253. if( !($fp = fopen( $filename, 'r' )) ) {
  1254. // die( 'Unable to open file' );
  1255. return FALSE;
  1256. }
  1257. // do version detection here
  1258. if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
  1259. return FALSE;
  1260. }
  1261. if ( $returnSchema )
  1262. {
  1263. $xmlstring = '';
  1264. while( $data = fread( $fp, 100000 ) ) {
  1265. $xmlstring .= $data;
  1266. }
  1267. return $xmlstring;
  1268. }
  1269. $this->success = 2;
  1270. $xmlParser = $this->create_parser();
  1271. // Process the file
  1272. while( $data = fread( $fp, 4096 ) ) {
  1273. if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
  1274. die( sprintf(
  1275. "XML error: %s at line %d",
  1276. xml_error_string( xml_get_error_code( $xmlParser) ),
  1277. xml_get_current_line_number( $xmlParser)
  1278. ) );
  1279. }
  1280. }
  1281. xml_parser_free( $xmlParser );
  1282. return $this->sqlArray;
  1283. }
  1284. /**
  1285. * Converts an XML schema string to SQL.
  1286. *
  1287. * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
  1288. * and generate the SQL necessary to create the database described by the schema.
  1289. * @see ParseSchema()
  1290. *
  1291. * @param string $xmlstring XML schema string.
  1292. * @param bool $returnSchema Return schema rather than parsing.
  1293. * @return array Array of SQL queries, ready to execute.
  1294. */
  1295. function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
  1296. if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
  1297. return FALSE;
  1298. }
  1299. // do version detection here
  1300. if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
  1301. return FALSE;
  1302. }
  1303. if ( $returnSchema )
  1304. {
  1305. return $xmlstring;
  1306. }
  1307. $this->success = 2;
  1308. $xmlParser = $this->create_parser();
  1309. if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
  1310. die( sprintf(
  1311. "XML error: %s at line %d",
  1312. xml_error_string( xml_get_error_code( $xmlParser) ),
  1313. xml_get_current_line_number( $xmlParser)
  1314. ) );
  1315. }
  1316. xml_parser_free( $xmlParser );
  1317. return $this->sqlArray;
  1318. }
  1319. /**
  1320. * Loads an XML schema from a file and converts it to uninstallation SQL.
  1321. *
  1322. * Call this method to load the specified schema (see the DTD for the proper format) from
  1323. * the filesystem and generate the SQL necessary to remove the database described.
  1324. * @see RemoveSchemaString()
  1325. *
  1326. * @param string $file Name of XML schema file.
  1327. * @param bool $returnSchema Return schema rather than parsing.
  1328. * @return array Array of SQL queries, ready to execute
  1329. */
  1330. function RemoveSchema( $filename, $returnSchema = FALSE ) {
  1331. return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
  1332. }
  1333. /**
  1334. * Converts an XML schema string to uninstallation SQL.
  1335. *
  1336. * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
  1337. * and generate the SQL necessary to uninstall the database described by the schema.
  1338. * @see RemoveSchema()
  1339. *
  1340. * @param string $schema XML schema string.
  1341. * @param bool $returnSchema Return schema rather than parsing.
  1342. * @return array Array of SQL queries, ready to execute.
  1343. */
  1344. function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
  1345. // grab current version
  1346. if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
  1347. return FALSE;
  1348. }
  1349. return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
  1350. }
  1351. /**
  1352. * Applies the current XML schema to the database (post execution).
  1353. *
  1354. * Call this method to apply the current schema (generally created by calling
  1355. * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes,
  1356. * and executing other SQL specified in the schema) after parsing.
  1357. * @see ParseSchema(), ParseSchemaString(), ExecuteInline()
  1358. *
  1359. * @param array $sqlArray Array of SQL statements that will be applied rather than
  1360. * the current schema.
  1361. * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
  1362. * @returns integer 0 if failure, 1 if errors, 2 if successful.
  1363. */
  1364. function ExecuteSchema( $sqlArray = NULL, $continueOnErr = NULL ) {
  1365. if( !is_bool( $continueOnErr ) ) {
  1366. $continueOnErr = $this->ContinueOnError();
  1367. }
  1368. if( !isset( $sqlArray ) ) {
  1369. $sqlArray = $this->sqlArray;
  1370. }
  1371. if( !is_array( $sqlArray ) ) {
  1372. $this->success = 0;
  1373. } else {
  1374. $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
  1375. }
  1376. return $this->success;
  1377. }
  1378. /**
  1379. * Returns the current SQL array.
  1380. *
  1381. * Call this method to fetch the array of SQL queries resulting from
  1382. * ParseSchema() or ParseSchemaString().
  1383. *
  1384. * @param string $format Format: HTML, TEXT, or NONE (PHP array)
  1385. * @return array Array of SQL statements or FALSE if an error occurs
  1386. */
  1387. function PrintSQL( $format = 'NONE' ) {
  1388. $sqlArray = null;
  1389. return $this->getSQL( $format, $sqlArray );
  1390. }
  1391. /**
  1392. * Saves the current SQL array to the local filesystem as a list of SQL queries.
  1393. *
  1394. * Call this method to save the array of SQL queries (generally resulting from a
  1395. * parsed XML schema) to the filesystem.
  1396. *
  1397. * @param string $filename Path and name where the file should be saved.
  1398. * @return boolean TRUE if save is successful, else FALSE.
  1399. */
  1400. function SaveSQL( $filename = './schema.sql' ) {
  1401. if( !isset( $sqlArray ) ) {
  1402. $sqlArray = $this->sqlArray;
  1403. }
  1404. if( !isset( $sqlArray ) ) {
  1405. return FALSE;
  1406. }
  1407. $fp = fopen( $filename, "w" );
  1408. foreach( $sqlArray as $key => $query ) {
  1409. fwrite( $fp, $query . ";\n" );
  1410. }
  1411. fclose( $fp );
  1412. }
  1413. /**
  1414. * Create an xml parser
  1415. *
  1416. * @return object PHP XML parser object
  1417. *
  1418. * @access private
  1419. */
  1420. function create_parser() {
  1421. // Create the parser
  1422. $xmlParser = xml_parser_create();
  1423. xml_set_object( $xmlParser, $this );
  1424. // Initialize the XML callback functions
  1425. xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
  1426. xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
  1427. return $xmlParser;
  1428. }
  1429. /**
  1430. * XML Callback to process start elements
  1431. *
  1432. * @access private
  1433. */
  1434. function _tag_open( &$parser, $tag, $attributes ) {
  1435. switch( strtoupper( $tag ) ) {
  1436. case 'TABLE':
  1437. $this->obj = new dbTable( $this, $attributes );
  1438. xml_set_object( $parser, $this->obj );
  1439. break;
  1440. case 'SQL':
  1441. if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
  1442. $this->obj = new dbQuerySet( $this, $attributes );
  1443. xml_set_object( $parser, $this->obj );
  1444. }
  1445. break;
  1446. default:
  1447. // print_r( array( $tag, $attributes ) );
  1448. }
  1449. }
  1450. /**
  1451. * XML Callback to process CDATA elements
  1452. *
  1453. * @access private
  1454. */
  1455. function _tag_cdata( &$parser, $cdata ) {
  1456. }
  1457. /**
  1458. * XML Callback to process end elements
  1459. *
  1460. * @access private
  1461. * @internal
  1462. */
  1463. function _tag_close( &$parser, $tag ) {
  1464. }
  1465. /**
  1466. * Converts an XML schema string to the specified DTD version.
  1467. *
  1468. * Call this method to convert a string containing an XML schema to a different AXMLS
  1469. * DTD version. For instance, to convert a schema created for an pre-1.0 version for
  1470. * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
  1471. * parameter is specified, the schema will be converted to the current DTD version.
  1472. * If the newFile parameter is provided, the converted schema will be written to the specified
  1473. * file.
  1474. * @see ConvertSchemaFile()
  1475. *
  1476. * @param string $schema String containing XML schema that will be converted.
  1477. * @param string $newVersion DTD version to convert to.
  1478. * @param string $newFile File name of (converted) output file.
  1479. * @return string Converted XML schema or FALSE if an error occurs.
  1480. */
  1481. function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
  1482. // grab current version
  1483. if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
  1484. return FALSE;
  1485. }
  1486. if( !isset ($newVersion) ) {
  1487. $newVersion = $this->schemaVersion;
  1488. }
  1489. if( $version == $newVersion ) {
  1490. $result = $schema;
  1491. } else {
  1492. $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
  1493. }
  1494. if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
  1495. fwrite( $fp, $result );
  1496. fclose( $fp );
  1497. }
  1498. return $result;
  1499. }
  1500. // compat for pre-4.3 - jlim
  1501. function _file_get_contents($path)
  1502. {
  1503. if (function_exists('file_get_contents')) return file_get_contents($path);
  1504. return join('',file($path));
  1505. }
  1506. /**
  1507. * Converts an XML schema file to the specified DTD version.
  1508. *
  1509. * Call this method to convert the specified XML schema file to a different AXMLS
  1510. * DTD version. For instance, to convert a schema created for an pre-1.0 version for
  1511. * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
  1512. * parameter is specified, the schema will be converted to the current DTD version.
  1513. * If the newFile parameter is provided, the converted schema will be written to the specified
  1514. * file.
  1515. * @see ConvertSchemaString()
  1516. *
  1517. * @param string $filename Name of XML schema file that will be converted.
  1518. * @param string $newVersion DTD version to convert to.
  1519. * @param string $newFile File name of (converted) output file.
  1520. * @return string Converted XML schema or FALSE if an error occurs.
  1521. */
  1522. function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
  1523. // grab current version
  1524. if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
  1525. return FALSE;
  1526. }
  1527. if( !isset ($newVersion) ) {
  1528. $newVersion = $this->schemaVersion;
  1529. }
  1530. if( $version == $newVersion ) {
  1531. $result = _file_get_contents( $filename );
  1532. // remove unicode BOM if present
  1533. if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
  1534. $result = substr( $result, 3 );
  1535. }
  1536. } else {
  1537. $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
  1538. }
  1539. if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
  1540. fwrite( $fp, $result );
  1541. fclose( $fp );
  1542. }
  1543. return $result;
  1544. }
  1545. function TransformSchema( $schema, $xsl, $schematype='string' )
  1546. {
  1547. // Fail if XSLT extension is not available
  1548. if( ! function_exists( 'xslt_create' ) ) {
  1549. return FALSE;
  1550. }
  1551. $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
  1552. // look for xsl
  1553. if( !is_readable( $xsl_file ) ) {
  1554. return FALSE;
  1555. }
  1556. switch( $schematype )
  1557. {
  1558. case 'file':
  1559. if( !is_readable( $schema ) ) {
  1560. return FALSE;
  1561. }
  1562. $schema = _file_get_contents( $schema );
  1563. break;
  1564. case 'string':
  1565. default:
  1566. if( !is_string( $schema ) ) {
  1567. return FALSE;
  1568. }
  1569. }
  1570. $arguments = array (
  1571. '/_xml' => $schema,
  1572. '/_xsl' => _file_get_contents( $xsl_file )
  1573. );
  1574. // create an XSLT processor
  1575. $xh = xslt_create ();
  1576. // set error handler
  1577. xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
  1578. // process the schema
  1579. $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments);
  1580. xslt_free ($xh);
  1581. return $result;
  1582. }
  1583. /**
  1584. * Processes XSLT transformation errors
  1585. *
  1586. * @param object $parser XML parser object
  1587. * @param integer $errno Error number
  1588. * @param integer $level Error level
  1589. * @param array $fields Error information fields
  1590. *
  1591. * @access private
  1592. */
  1593. function xslt_error_handler( $parser, $errno, $level, $fields ) {
  1594. if( is_array( $fields ) ) {
  1595. $msg = array(
  1596. 'Message Type' => ucfirst( $fields['msgtype'] ),
  1597. 'Message Code' => $fields['code'],
  1598. 'Message' => $fields['msg'],
  1599. 'Error Number' => $errno,
  1600. 'Level' => $level
  1601. );
  1602. switch( $fields['URI'] ) {
  1603. case 'arg:/_xml':
  1604. $msg['Input'] = 'XML';
  1605. break;
  1606. case 'arg:/_xsl':
  1607. $msg['Input'] = 'XSL';
  1608. break;
  1609. default:
  1610. $msg['Input'] = $fields['URI'];
  1611. }
  1612. $msg['Line'] = $fields['line'];
  1613. } else {
  1614. $msg = array(
  1615. 'Message Type' => 'Error',
  1616. 'Error Number' => $errno,
  1617. 'Level' => $level,
  1618. 'Fields' => var_export( $fields, TRUE )
  1619. );
  1620. }
  1621. $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
  1622. . '<table>' . "\n";
  1623. foreach( $msg as $label => $details ) {
  1624. $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
  1625. }
  1626. $error_details .= '</table>';
  1627. trigger_error( $error_details, E_USER_ERROR );
  1628. }
  1629. /**
  1630. * Returns the AXMLS Schema Version of the requested XML schema file.
  1631. *
  1632. * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
  1633. * @see SchemaStringVersion()
  1634. *
  1635. * @param string $filename AXMLS schema file
  1636. * @return string Schema version number or FALSE on error
  1637. */
  1638. function SchemaFileVersion( $filename ) {
  1639. // Open the file
  1640. if( !($fp = fopen( $filename, 'r' )) ) {
  1641. // die( 'Unable to open file' );
  1642. return FALSE;
  1643. }
  1644. // Process the file
  1645. while( $data = fread( $fp, 4096 ) ) {
  1646. if( preg_match( $this->versionRegex, $data, $matches ) ) {
  1647. return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
  1648. }
  1649. }
  1650. return FALSE;
  1651. }
  1652. /**
  1653. * Returns the AXMLS Schema Version of the provided XML schema string.
  1654. *
  1655. * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
  1656. * @see SchemaFileVersion()
  1657. *
  1658. * @param string $xmlstring XML schema string
  1659. * @return string Schema version number or FALSE on error
  1660. */
  1661. function SchemaStringVersion( $xmlstring ) {
  1662. if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
  1663. return FALSE;
  1664. }
  1665. if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
  1666. return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
  1667. }
  1668. return FALSE;
  1669. }
  1670. /**
  1671. * Extracts an XML schema from an existing database.
  1672. *
  1673. * Call this method to create an XML schema string from an existing database.
  1674. * If the data parameter is set to TRUE, AXMLS will include the data from the database
  1675. * in the schema.
  1676. *
  1677. * @param boolean $data Include data in schema dump
  1678. * @return string Generated XML schema
  1679. */
  1680. function ExtractSchema( $data = FALSE ) {
  1681. $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
  1682. $schema = '<?xml version="1.0"?>' . "\n"
  1683. . '<schema version="' . $this->schemaVersion . '">' . "\n";
  1684. if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) {
  1685. foreach( $tables as $table ) {
  1686. $schema .= ' <table name="' . $table . '">' . "\n";
  1687. // grab details from database
  1688. $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE 1=1' );
  1689. $fields = $this->db->MetaColumns( $table );
  1690. $indexes = $this->db->MetaIndexes( $table );
  1691. if( is_array( $fields ) ) {
  1692. foreach( $fields as $details ) {
  1693. $extra = '';
  1694. $content = array();
  1695. if( $details->max_length > 0 ) {
  1696. $extra .= ' size="' . $details->max_length . '"';
  1697. }
  1698. if( $details->primary_key ) {
  1699. $content[] = '<KEY/>';
  1700. } elseif( $details->not_null ) {
  1701. $content[] = '<NOTNULL/>';
  1702. }
  1703. if( $details->has_default ) {
  1704. $content[] = '<DEFAULT value="' . $details->default_value . '"/>';
  1705. }
  1706. if( $details->auto_increment ) {
  1707. $content[] = '<AUTOINCREMENT/>';
  1708. }
  1709. // this stops the creation of 'R' columns,
  1710. // AUTOINCREMENT is used to create auto columns
  1711. $details->primary_key = 0;
  1712. $type = $rs->MetaType( $details );
  1713. $schema .= ' <field name="' . $details->name . '" type="' . $type . '"' . $extra . '>';
  1714. if( !empty( $content ) ) {
  1715. $schema .= "\n " . implode( "\n ", $content ) . "\n ";
  1716. }
  1717. $schema .= '</field>' . "\n";
  1718. }
  1719. }
  1720. if( is_array( $indexes ) ) {
  1721. foreach( $indexes as $index => $details ) {
  1722. $schema .= ' <index name="' . $index . '">' . "\n";
  1723. if( $details['unique'] ) {
  1724. $schema .= ' <UNIQUE/>' . "\n";
  1725. }
  1726. foreach( $details['columns'] as $column ) {
  1727. $schema .= ' <col>' . $column . '</col>' . "\n";
  1728. }
  1729. $schema .= ' </index>' . "\n";
  1730. }
  1731. }
  1732. if( $data ) {
  1733. $rs = $this->db->Execute( 'SELECT * FROM ' . $table );
  1734. if( is_object( $rs ) ) {
  1735. $schema .= ' <data>' . "\n";
  1736. while( $row = $rs->FetchRow() ) {
  1737. foreach( $row as $key => $val ) {
  1738. $row[$key] = htmlentities($val);
  1739. }
  1740. $schema .= ' <row><f>' . implode( '</f><f>', $row ) . '</f></row>' . "\n";
  1741. }
  1742. $schema .= ' </data>' . "\n";
  1743. }
  1744. }
  1745. $schema .= ' </table>' . "\n";
  1746. }
  1747. }
  1748. $this->db->SetFetchMode( $old_mode );
  1749. $schema .= '</schema>';
  1750. return $schema;
  1751. }
  1752. /**
  1753. * Sets a prefix for database objects
  1754. *
  1755. * Call this method to set a standard prefix that will be prepended to all database tables
  1756. * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
  1757. *
  1758. * @param string $prefix Prefix that will be prepended.
  1759. * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
  1760. * @return boolean TRUE if successful, else FALSE
  1761. */
  1762. function SetPrefix( $prefix = '', $underscore = TRUE ) {
  1763. switch( TRUE ) {
  1764. // clear prefix
  1765. case empty( $prefix ):
  1766. logMsg( 'Cleared prefix' );
  1767. $this->objectPrefix = '';
  1768. return TRUE;
  1769. // prefix too long
  1770. case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
  1771. // prefix contains invalid characters
  1772. case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
  1773. logMsg( 'Invalid prefix: ' . $prefix );
  1774. return FALSE;
  1775. }
  1776. if( $underscore AND substr( $prefix, -1 ) != '_' ) {
  1777. $prefix .= '_';
  1778. }
  1779. // prefix valid
  1780. logMsg( 'Set prefix: ' . $prefix );
  1781. $this->objectPrefix = $prefix;
  1782. return TRUE;
  1783. }
  1784. /**
  1785. * Returns an object name with the current prefix prepended.
  1786. *
  1787. * @param string $name Name
  1788. * @return string Prefixed name
  1789. *
  1790. * @access private
  1791. */
  1792. function prefix( $name = '' ) {
  1793. // if prefix is set
  1794. if( !empty( $this->objectPrefix ) ) {
  1795. // Prepend the object prefix to the table name
  1796. // prepend after quote if used
  1797. return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
  1798. }
  1799. // No prefix set. Use name provided.
  1800. return $name;
  1801. }
  1802. /**
  1803. * Checks if element references a specific platform
  1804. *
  1805. * @param string $platform Requested platform
  1806. * @returns boolean TRUE if platform check succeeds
  1807. *
  1808. * @access private
  1809. */
  1810. function supportedPlatform( $platform = NULL ) {
  1811. $regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/';
  1812. if( !isset( $platform ) OR preg_match( $regex, $platform ) ) {
  1813. logMsg( "Platform $platform is supported" );
  1814. return TRUE;
  1815. } else {
  1816. logMsg( "Platform $platform is NOT supported" );
  1817. return FALSE;
  1818. }
  1819. }
  1820. /**
  1821. * Clears the array of generated SQL.
  1822. *
  1823. * @access private
  1824. */
  1825. function clearSQL() {
  1826. $this->sqlArray = array();
  1827. }
  1828. /**
  1829. * Adds SQL into the SQL array.
  1830. *
  1831. * @param mixed $sql SQL to Add
  1832. * @return boolean TRUE if successful, else FALSE.
  1833. *
  1834. * @access private
  1835. */
  1836. function addSQL( $sql = NULL ) {
  1837. if( is_array( $sql ) ) {
  1838. foreach( $sql as $line ) {
  1839. $this->addSQL( $line );
  1840. }
  1841. return TRUE;
  1842. }
  1843. if( is_string( $sql ) ) {
  1844. $this->sqlArray[] = $sql;
  1845. // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
  1846. if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
  1847. $saved = $this->db->debug;
  1848. $this->db->debug = $this->debug;
  1849. $ok = $this->db->Execute( $sql );
  1850. $this->db->debug = $saved;
  1851. if( !$ok ) {
  1852. if( $this->debug ) {
  1853. ADOConnection::outp( $this->db->ErrorMsg() );
  1854. }
  1855. $this->success = 1;
  1856. }
  1857. }
  1858. return TRUE;
  1859. }
  1860. return FALSE;
  1861. }
  1862. /**
  1863. * Gets the SQL array in the specified format.
  1864. *
  1865. * @param string $format Format
  1866. * @return mixed SQL
  1867. *
  1868. * @access private
  1869. */
  1870. function getSQL( $format = NULL, $sqlArray = NULL ) {
  1871. if( !is_array( $sqlArray ) ) {
  1872. $sqlArray = $this->sqlArray;
  1873. }
  1874. if( !is_array( $sqlArray ) ) {
  1875. return FALSE;
  1876. }
  1877. switch( strtolower( $format ) ) {
  1878. case 'string':
  1879. case 'text':
  1880. return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
  1881. case'html':
  1882. return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
  1883. }
  1884. return $this->sqlArray;
  1885. }
  1886. /**
  1887. * Destroys an adoSchema object.
  1888. *
  1889. * Call this method to clean up after an adoSchema object that is no longer in use.
  1890. * @deprecated adoSchema now cleans up automatically.
  1891. */
  1892. function Destroy() {
  1893. if ($this->mgq !== false) {
  1894. ini_set('magic_quotes_runtime', $this->mgq );
  1895. }
  1896. }
  1897. }
  1898. /**
  1899. * Message logging function
  1900. *
  1901. * @access private
  1902. */
  1903. function logMsg( $msg, $title = NULL, $force = FALSE ) {
  1904. if( XMLS_DEBUG or $force ) {
  1905. echo '<pre>';
  1906. if( isset( $title ) ) {
  1907. echo '<h3>' . htmlentities( $title ) . '</h3>';
  1908. }
  1909. if( is_object( $this ) ) {
  1910. echo '[' . get_class( $this ) . '] ';
  1911. }
  1912. print_r( $msg );
  1913. echo '</pre>';
  1914. }
  1915. }