Source for file schema-defs.php

Documentation is available at schema-defs.php

  1. <?php
  2. /* ******************************************************************** */
  3. /* CATALYST PHP Source Code */
  4. /* -------------------------------------------------------------------- */
  5. /* This program is free software; you can redistribute it and/or modify */
  6. /* it under the terms of the GNU General Public License as published by */
  7. /* the Free Software Foundation; either version 2 of the License, or */
  8. /* (at your option) any later version. */
  9. /* */
  10. /* This program is distributed in the hope that it will be useful, */
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  13. /* GNU General Public License for more details. */
  14. /* */
  15. /* You should have received a copy of the GNU General Public License */
  16. /* along with this program; if not, write to: */
  17. /* The Free Software Foundation, Inc., 59 Temple Place, Suite 330, */
  18. /* Boston, MA 02111-1307 USA */
  19. /* -------------------------------------------------------------------- */
  20. /* */
  21. /* Filename: schema-defs.php */
  22. /* Author: Paul Waite */
  23. /* Description: Definitions for managing DATABASE SCHEMAS */
  24. /* The schema class can be used to read in a database */
  25. /* table-by-table, or all at once. */
  26. /* */
  27. /* The main use of this class is to provide a means of */
  28. /* developing a child-class which reads a specific type */
  29. /* of database (eg. see pg-schema-defs.php). */
  30. /* */
  31. /* ******************************************************************** */
  32. /** @package database *//** Run getchema() in recusrive mode - follow foreign keys */
  33. ("ALL", "all");
  34.  
  35. /** Run getschema() to get primary key(s) only */
  36. ("PRIMARY_KEY_ONLY", "p");
  37.  
  38. /** Run getschema() to get only current table fields (no recursion) */
  39. ("FIELDS_ONLY", "f");
  40.  
  41. // ----------------------------------------------------------------------
  42. /** Defines a virtual object which is used to denote something which
  43. * is a part of an existing database schema.
  44. * @package database
  45. */
  46. class SchemaObject {
  47. /** Reference to the schema object this belongs to */
  48.  
  49. var $schema;
  50. /** Name of this schema object */
  51.  
  52. var $name = "";
  53. // ....................................................................
  54. /** Constructor
  55. * Every schema object must belong to a schema. This is passed as the first
  56. * argument, as an object reference. It must also have a name, and this is
  57. * always passed as the second argument, a string.
  58. * @param reference $schema Reference to a schema object this object belongs to
  59. * @param string $name The name of this object
  60. */
  61. function SchemaObject($schema, $name) {
  62. $this->schema = $schema;
  63. $this->name = strtolower($name);
  64. }
  65. } // class SchemaObject
  66. // ----------------------------------------------------------------------
  67.  
  68. /** Defines a database sequence.
  69. * @package database
  70. */
  71. class dbsequence extends SchemaObject {
  72. // ....................................................................
  73. function dbsequence(&$schema, $name) {
  74. $this->SchemaObject($schema, $name);
  75. }
  76. // ....................................................................
  77. /**
  78. * Acquires the schema from database metadata.
  79. * NB: Override this function to get schema info per DB type.
  80. */
  81. function getschema() { }
  82. // ....................................................................
  83. // Dump ascii description of this sequence to stdout.
  84. function dump() {
  85. $s = "Sequence $this->name";
  86. return "$s\n";
  87. }
  88. // ....................................................................
  89. // Return SQL required to create this sequence.
  90. function create() {
  91. $s .= "create sequence \"$this->name\"";
  92. $s .= ";\n";
  93. return $s;
  94. }
  95. // ....................................................................
  96. // Return SQL to drop this sequence.
  97. function drop() {
  98. $s .= "drop sequence $this->name;\n";
  99. return $s;
  100. }
  101. }
  102.  
  103. // ----------------------------------------------------------------------
  104. /** Defines a database function (procedure).
  105. * @package database
  106. */
  107. class dbfunction extends SchemaObject {
  108. var $return_type = "";
  109. var $src = "";
  110. var $arg_types = array();
  111. var $language = "";
  112.  
  113. // ....................................................................
  114. function dbfunction(&$schema, $name, $returns="", $src="", $args="", $lang="plpgsql") {
  115. $this->SchemaObject($schema, $name);
  116. $this->set($returns, $src, $args, $lang);
  117. }
  118. // ....................................................................
  119. /** Set the vars for this function */
  120.  
  121. function set($returns="", $src="", $args="", $lang="plpgsql") {
  122. $this->return_type = $returns;
  123. $this->src = str_replace("'", "''", $src);
  124. if (is_array($args)) $this->arg_types = $args;
  125. $this->language = $lang;
  126. }
  127. // ....................................................................
  128. /**
  129. * Acquires the schema from database metadata.
  130. * NB: Override this function to get schema info per DB type.
  131. */
  132. function getschema() { }
  133. // ....................................................................
  134. /** Dump ascii description of this function to stdout. */
  135.  
  136. function dump() {
  137. $s = "Function $this->name returns $this->returns language='$this->language'";
  138. return "$s\n";
  139. }
  140. // ....................................................................
  141. /** Return the types parameter list, including brackets. */
  142.  
  143. function parameters() {
  144. $s = "";
  145. $s .= " (";
  146. if (count($this->arg_types) > 0) {
  147. foreach ($this->arg_types as $arg) {
  148. $s .= "$arg,";
  149. }
  150. $s = substr($s, 0, -1);
  151. }
  152. $s .= ")";
  153. return $s;
  154. }
  155. // ....................................................................
  156. // Return SQL required to create this function.
  157. function create() {
  158. $s .= "create function \"$this->name\"";
  159. $s .= $this->parameters();
  160. $s .= " returns $this->return_type";
  161. $s .= " as '$this->src'";
  162. $s .= " language $this->language";
  163. $s .= ";\n";
  164. return $s;
  165. }
  166. // ....................................................................
  167. // Return SQL to drop this function..
  168. function drop() {
  169. $s .= "drop function $this->name";
  170. $s .= $this->parameters();
  171. $s .= ";\n";
  172. return $s;
  173. }
  174. } // class dbfunction
  175. // ----------------------------------------------------------------------
  176.  
  177. /** Defines a database index.
  178. * @package database
  179. */
  180. class dbindex extends SchemaObject {
  181. /** Name of table index is built on */
  182.  
  183. var $tablename;
  184. /** Fieldnames in the index */
  185.  
  186. var $fieldnames = array();
  187. /** True if index is for a primary key */
  188.  
  189. var $primary = false;
  190. /** True if index is unique */
  191.  
  192. var $unique = false;
  193. // ....................................................................
  194. function dbindex(&$schema, $name, $tablename="", $flds="", $primary=false, $unique=false) {
  195. $this->SchemaObject($schema, $name);
  196. $this->set($tablename, $flds, $primary, $unique);
  197. }
  198. // ....................................................................
  199. /** Set index variables. */
  200.  
  201. function set($tablename="", $flds="", $primary=false, $unique=false) {
  202. $this->tablename = $tablename;
  203. if (is_array($flds)) $this->fieldnames = $flds;
  204. $this->primary = $primary;
  205. $this->unique = $unique;
  206. }
  207. // ....................................................................
  208. /**
  209. * Acquires the schema from database metadata.
  210. * NB: Override this function to get schema info per DB type.
  211. */
  212. function getschema() { }
  213. // ....................................................................
  214. /** Dump ascii description of this index to stdout. */
  215.  
  216. function dump() {
  217. $bits = explode("create", $this->create());
  218. return str_replace(";", "", trim($bits[1])) . "\n";
  219. }
  220. // ....................................................................
  221. /** Return SQL required to create this index. */
  222.  
  223. function create() {
  224. $s = "";
  225. $s .= "create";
  226. if ($this->unique) $s .= " unique";
  227. $s .= " index $this->name on " . $this->tablename;
  228. if ($this->access_method != "") {
  229. $s .= " using $this->access_method";
  230. }
  231. $s .= " (";
  232. if (count($this->fieldnames) > 0) {
  233. $flds = implode(",", $this->fieldnames);
  234. $s .= $flds;
  235. }
  236. $s .= ");\n";
  237. return $s;
  238. }
  239. // ....................................................................
  240. // Return SQL to drop this index.
  241. function drop() {
  242. $s = "drop index $this->name;\n";
  243. return $s;
  244. }
  245. } // class dbindex
  246. // ----------------------------------------------------------------------
  247.  
  248. /** Defines a database constraint.
  249. * @package database
  250. */
  251. class dbconstraint extends SchemaObject {
  252. /** Type of constraint 'c' - check, 'p' - pk, 'f' - fk */
  253.  
  254. var $type = "";
  255. /** Name of table constraint is applied to */
  256.  
  257. var $tablename = "";
  258. /** Foreign key table name constraint refers to */
  259.  
  260. var $fk_tablename = "";
  261. /** True if constraint is deferrable */
  262.  
  263. var $deferrable = false;
  264. /** True if constraint is initially deferred */
  265.  
  266. var $deferred = false;
  267. /** Array of table field names in constraint */
  268.  
  269. var $fieldnames = array();
  270. /** Array of referenced foreign key fieldnames */
  271.  
  272. var $fk_fieldnames = array();
  273. /** Action to take on update */
  274.  
  275. var $update_action = "";
  276. /** Action to take on delete */
  277.  
  278. var $delete_action = "";
  279. /** Match type for keys */
  280.  
  281. var $match_type = "";
  282. /** Check constraint source */
  283.  
  284. var $cksrc = "";
  285. // ....................................................................
  286. function dbconstraint(&$schema, $name, $type="p", $tablename="", $fktablename="", $flds="",
  287. $fkflds="", $updact="", $delact="", $match="", $cksrc="") {
  288. $this->SchemaObject($schema, $name);
  289. $this->set(
  290. $type,
  291. $tablename,
  292. $fktablename,
  293. $flds,
  294. $fkflds,
  295. $updact,
  296. $delact,
  297. $match,
  298. $cksrc
  299. );
  300. }
  301. // ....................................................................
  302. /** Set constraint variables. */
  303.  
  304. function set(
  305. $type,
  306. $tablename="",
  307. $fktablename="",
  308. $flds="",
  309. $fkflds="",
  310. $updact="",
  311. $delact="",
  312. $match="",
  313. $cksrc="",
  314. $deferrable=false,
  315. $deferred=false
  316. ) {
  317. // The "!" implies 'leave as it is' ..
  318. if ($type != "!") $this->type = $type;
  319. if ($tablename != "!") $this->tablename = $tablename;
  320. if ($fktablename != "!") $this->fk_tablename = $fktablename;
  321. if (is_array($flds)) $this->fieldnames = $flds;
  322. if (is_array($fkflds)) $this->fk_fieldnames = $fkflds;
  323. if ($updact != "!") $this->update_action = $updact;
  324. if ($delact != "!") $this->delete_action = $delact;
  325. if ($match != "!") $this->match_type = $match;
  326. if ($cksrc != "!") $this->cksrc = $cksrc;
  327. if ($deferrable != "!") $this->deferrable = $deferrable;
  328. if ($deferred != "!") $this->deferred = $deferred;
  329. }
  330. // ....................................................................
  331. /**
  332. * Acquires the schema from database metadata.
  333. * NB: Override this function to get schema info per DB type.
  334. */
  335. function getschema() { }
  336. // ....................................................................
  337. /** Dump ascii description of this constraint to stdout. */
  338.  
  339. function dump() {
  340. $bits = explode("add", $this->create());
  341. return str_replace(";", "", trim($bits[1])) . "\n";
  342. }
  343. // ....................................................................
  344. /** Return SQL required to create this as an inline table constraint */
  345.  
  346. function create_inline() {
  347. return $this->create(false);
  348. }
  349. // ....................................................................
  350. /** Return SQL required to create this constraint outside the table */
  351.  
  352. function create($outside_table=true) {
  353. $s = "";
  354. switch ($this->type) {
  355. // PRIMARY KEY CONSTRAINT
  356. case "p":
  357. if ($outside_table) {
  358. if ($this->tablename == "") return $s;
  359. $s .= "alter table " . $this->tablename . "\n";
  360. $s .= " add ";
  361. }
  362. $s .= "constraint $this->name primary key";
  363. $s .= $this->fields();
  364. break;
  365.  
  366. // CHECK CONSTRAINT
  367. case "c":
  368. if ($outside_table) {
  369. if ($this->tablename == "") return $s;
  370. $s .= "alter table " . $this->tablename . "\n";
  371. $s .= " add ";
  372. }
  373. $s .= "constraint $this->name check $this->cksrc";
  374. break;
  375.  
  376. // FOREIGN KEY CONSTRAINT
  377. case "f":
  378. if ($outside_table) {
  379. if ($this->tablename == "" || $this->fk_tablename == "") return $s;
  380. $s .= "alter table " . $this->tablename . "\n";
  381. $s .= " add ";
  382. }
  383. $s .= "constraint $this->name foreign key";
  384. $s .= $this->fields();
  385. $s .= " references " . $this->fk_tablename;
  386. $s .= $this->fk_fields();
  387.  
  388. // MATCH TYPE
  389. switch ($this->match_type) {
  390. case "f":
  391. $s .= " match full";
  392. break;
  393. }
  394.  
  395. // UPDATE ACTION
  396. if ($this->update_action != "") {
  397. $act = " on update";
  398. switch ($this->update_action) {
  399. case "a": $act .= " no action"; break;
  400. case "c": $act .= " cascade"; break;
  401. case "n": $act .= " set null"; break;
  402. case "r": $act .= " restrict"; break;
  403. case "d": $act .= " set default"; break;
  404. default: $act = "";
  405. }
  406. $s .= $act;
  407. }
  408.  
  409. // DELETE ACTION
  410. if ($this->delete_action != "") {
  411. $act = " on delete";
  412. switch ($this->delete_action) {
  413. case "a": $act .= " no action"; break;
  414. case "c": $act .= " cascade"; break;
  415. case "n": $act .= " set null"; break;
  416. case "r": $act .= " restrict"; break;
  417. case "d": $act .= " set default"; break;
  418. default: $act = "";
  419. }
  420. $s .= $act;
  421. }
  422.  
  423. // DEFERRABLE MODES
  424. if ($this->deferrable) {
  425. $s .= " deferrable";
  426. if ($this->deferred) {
  427. $s .= " initially deferred";
  428. }
  429. }
  430. break;
  431. }
  432. $s .= ";\n";
  433. return $s;
  434. }
  435. // ....................................................................
  436. // Unpacks the table fields array and returns '(field1,field2, ...)'..
  437. // These are the fields on the table the constraint is on.
  438. function fields() {
  439. $s .= "";
  440. if (count($this->fieldnames) > 0) {
  441. $s .= " (" . implode(",", $this->fieldnames) . ")";
  442. }
  443. return $s;
  444. }
  445. // ....................................................................
  446. // Unpacks the foreign key fields array and returns '(field1,field2, ...)'..
  447. // These are the fields on the table that the constraint references.
  448. function fk_fields() {
  449. $s .= "";
  450. if (count($this->fk_fieldnames) > 0) {
  451. $s .= " (" . implode(",", $this->fk_fieldnames) . ")";
  452. }
  453. return $s;
  454. }
  455. // ....................................................................
  456. // Return SQL to drop this constraint.
  457. function drop() {
  458. switch ($this->type) {
  459. case "p":
  460. case "f":
  461. case "c":
  462. $s .= "alter table " . $this->tablename . "\n";
  463. $s .= " drop constraint $this->name";
  464. $s .= " restrict;\n";
  465. break;
  466. }
  467. return $s;
  468. }
  469. // ....................................................................
  470. // Returns true if the given constraint matches this one in terms of
  471. // functionality. This allows you to identify constraints that are
  472. // the same apart from the naming.
  473. function matches($con) {
  474. if ($this->type != $con->type) return false;
  475. if ($this->tablename != $con->tablename) return false;
  476. if ($this->fk_tablename != $con->fk_tablename) return false;
  477. if ($this->deferrable != $con->deferrable) return false;
  478. if ($this->deferred != $con->deferred) return false;
  479. if ($this->fields() != $con->fields()) return false;
  480. if ($this->fk_fields() != $con->fk_fields()) return false;
  481. if ($this->update_action != $con->update_action) return false;
  482. if ($this->delete_action != $con->delete_action) return false;
  483. if ($this->match_type != $con->match_type) return false;
  484. if ($this->cksrc != $con->cksrc) return false;
  485. return true;
  486. }
  487. } // class dbconstraint
  488. // ----------------------------------------------------------------------
  489.  
  490. /** Defines a database trigger.
  491. * @package database
  492. */
  493. class dbtrigger extends SchemaObject {
  494. /** When trigger fires. If true BEFORE, else AFTER event */
  495.  
  496. var $before = true;
  497. /** If true, fire trigger on INSERT */
  498.  
  499. var $oninsert = false;
  500. /** If true, fire trigger on DELETE */
  501.  
  502. var $ondelete = false;
  503. /** If true, fire trigger on UPDATE */
  504.  
  505. var $onupdate = false;
  506. /** If true, execute func for EACH ROW else EACH STATEMENT */
  507.  
  508. var $eachrow = false;
  509. /** Name of table to apply trigger to */
  510.  
  511. var $tablename;
  512. /** Name of function to call when triggered */
  513.  
  514. var $funcname;
  515. /** Arguments to pass to the function */
  516.  
  517. var $args = array();
  518. // ....................................................................
  519. function dbtrigger(
  520. &$schema,
  521. $name,
  522. $before=true,
  523. $oninsert=false,
  524. $ondelete=false,
  525. $onupdate=false,
  526. $eachrow=false,
  527. $tablename="",
  528. $funcname="",
  529. $args=""
  530. ) {
  531. $this->SchemaObject($schema, $name);
  532. $this->set($before, $oninsert, $ondelete, $onupdate, $eachrow, $tablename, $funcname, $args);
  533. }
  534. // ....................................................................
  535. /** Set the vars for this trigger */
  536.  
  537. function set(
  538. $before=true,
  539. $oninsert=false,
  540. $ondelete=false,
  541. $onupdate=false,
  542. $eachrow=false,
  543. $tablename="",
  544. $funcname="",
  545. $args=""
  546. ) {
  547. $this->before = $before;
  548. $this->oninsert = $oninsert;
  549. $this->ondelete = $ondelete;
  550. $this->onupdate = $onupdate;
  551. $this->eachrow = $eachrow;
  552. $this->tablename = $tablename;
  553. $this->funcname = $funcname;
  554. if (is_array($args)) $this->args = $args;
  555. }
  556. // ....................................................................
  557. /**
  558. * Acquires the schema from database metadata.
  559. * NB: Override this function to get schema info per DB type.
  560. */
  561. function getschema() { }
  562. // ....................................................................
  563. /** Dump ascii description of this trigger to stdout. */
  564.  
  565. function dump() {
  566. $s = "trigger $this->name on " . $this->tablename . " executing function " . $this->funcname . "()";
  567. return "$s\n";
  568. }
  569. // ....................................................................
  570. /** Return SQL required to create this trigger. */
  571.  
  572. function create() {
  573. $s = "";
  574. $s .= "create";
  575. $s .= " trigger $this->name";
  576. if ($this->before) $s .= " before ";
  577. else $s .= " after ";
  578. $event = array();
  579. if ($this->oninsert) $event[] = "insert";
  580. if ($this->ondelete) $event[] = "delete";
  581. if ($this->onupdate) $event[] = "update";
  582. $s .= implode(" or ", $event);
  583. $s .= " on " . $this->tablename;
  584. if ($this->eachrow) $s .= " for each row";
  585. else $s = " for each statement";
  586. $s .= " execute procedure $this->funcname";
  587. $s .= " (";
  588. if (count($this->args) > 0) {
  589. $s .= implode(",", $this->args);
  590. }
  591. $s .= ");\n";
  592. return $s;
  593. }
  594. // ....................................................................
  595. // Return SQL to drop this trigger.
  596. function drop() {
  597. $s = "drop trigger $this->name on $this->tablename;\n";
  598. return $s;
  599. }
  600. } // class dbtrigger
  601. // ----------------------------------------------------------------------
  602.  
  603. /** Class describing a database field of a table.
  604. * @package database
  605. */
  606. class dbfield extends SchemaObject {
  607. var $num = 0;
  608. var $type = "";
  609. var $default = "";
  610. var $notnull = false;
  611. var $ispkey = false;
  612. var $constraints = array();
  613. // ....................................................................
  614. function dbfield(&$schema, $name, $num, $type, $default="", $notnull=false, $ispkey=false) {
  615. $this->SchemaObject($schema, $name);
  616. $this->num = $num;
  617. $this->type = $type;
  618. $this->default = $default;
  619. $this->notnull = $notnull;
  620. $this->ispkey = $ispkey;
  621. }
  622. // ....................................................................
  623. /** Dump field description to stdout. */
  624.  
  625. function dump() {
  626. $s = "$this->name $this->type";
  627. if ($this->default != "") $s .= " DEFAULT $this->default";
  628. if ($this->notnull) $s .= " NOT NULL";
  629. if ($this->ispkey) $s .= " (pk)";
  630. return "$s\n";
  631. }
  632. // ....................................................................
  633. /**
  634. * Return the generic type of the field. The generic types are as
  635. * follows:
  636. * text Fixed or varying length strings
  637. * numeric Integers, real numbers or money
  638. * datetime Times, dates date-times
  639. * logical Boolean or bit field (true/false)
  640. *
  641. * You should override this method to return the appropriate generic
  642. * field types from this list, for your database type.
  643. * NB: Override this function to get schema info per DB type.
  644. */
  645. function generic_type() {
  646. $gtype = "";
  647. $typematch = array(
  648. "text" => "char|varchar|character",
  649. "numeric" => "int|integer|float|real|dec|decimal",
  650. "datetime" => "datetime|date|time|timestamp",
  651. "logical" => "bit",
  652. "" => ".*"
  653. );
  654.  
  655. foreach ($typematch as $gentype => $pattern) {
  656. if (preg_match("/$pattern/i", $this->type)) {
  657. $gtype = $gentype;
  658. break;
  659. }
  660. }
  661. return $gtype;
  662. }
  663. // ....................................................................
  664. /**
  665. * Return true if the field is of an integer class.
  666. * NB: Override this function to get schema info per DB type.
  667. */
  668. function is_integer_class() {
  669. $pattern = "int|integer";
  670. return preg_match("/$pattern/i", $this->type);
  671. }
  672. // ....................................................................
  673. /**
  674. * Return true if the field is of a 'serial' class. This is a pseudo
  675. * class of types which encapsulates integer fields which are able
  676. * to auto-increment themselves when records are inserted.
  677. * NB: Override this function to get schema info per DB type.
  678. */
  679. function is_serial_class() {
  680. $pattern = "db-specific type";
  681. return preg_match("/$pattern/i", $this->type);
  682. }
  683. // ....................................................................
  684. /**
  685. * Return SQL to create this field in a table. This represents a
  686. * portion of the CREATE TABLE script pertaining to this field and
  687. * it comprises field name, type, and constraints.
  688. * @return string SQL to create field inside a create table statement.
  689. */
  690. function create() {
  691. $s = "";
  692. $s .= " \"$this->name\" $this->type";
  693. if ($this->notnull) $s .= " not null";
  694. if ($this->default != "") $s .= " default $this->default";
  695. $s .= $this->create_constraints();
  696. return $s;
  697. }
  698. // ....................................................................
  699. /** Return SQL to create all constraints for this field..
  700. * @return string SQL to create all field constraints.
  701. */
  702. function create_constraints() {
  703. $s = "";
  704. foreach ($this->constraints as $con) {
  705. $s .= "\n" . $con->create_inline();
  706. }
  707. return $s;
  708. }
  709. // ....................................................................
  710. /** Return the SQL to drop this field. */
  711.  
  712. function drop() {
  713. $s .= "drop column $this->name;";
  714. return $s;
  715. }
  716. // ....................................................................
  717. /** Return true if field constraints match those passed in.
  718. * @param object $field Field object to check matching constraints on
  719. * @return boolean True if $field's constraints match ours
  720. */
  721. function constraints_match($field) {
  722. $matched = true;
  723. if (count($this->constraints) != count($field->constraints)) {
  724. $matched = false;
  725. }
  726. else {
  727. foreach ($this->constraints as $con) {
  728. if (isset($field->constraints[$con->name])) {
  729. $fcon = $field->constraints[$con->name];
  730. if (!$fcon->matches($con)) {
  731. $matched = false;
  732. break;
  733. }
  734. }
  735. else {
  736. $matched = false;
  737. break;
  738. }
  739. } // foreach
  740. }
  741. return $matched;
  742. }
  743. } // class dbfield
  744. // ----------------------------------------------------------------------
  745.  
  746. /** Class describing a database table.
  747. * @package database
  748. */
  749. class dbtable extends SchemaObject {
  750. /** Array of field attnum's which are primary keys in table */
  751.  
  752. var $pkey = array();
  753. /** Array of field objects */
  754.  
  755. var $fields = array();
  756. /** Array of constraints on this table */
  757.  
  758. var $constraints = array();
  759. /** Array of indexes on this table */
  760.  
  761. var $indexes = array();
  762. // ....................................................................
  763. /** Construct a table of given name and array of primary key fields.
  764. * @param string $name The name of the table
  765. * @param array $pkey The array of pkeys is actually a list of integers, each being
  766. * the enumerated order of the field which is part of the key.
  767. * @param integer $dbversion Optional database version information
  768. */
  769. function dbtable(&$schema, $name) {
  770. $this->SchemaObject($schema, $name);
  771. }
  772. // ....................................................................
  773. /**
  774. * Acquires the schema from database metadata.
  775. * NB: Override this function to get schema info per DB type.
  776. */
  777. function getschema() { }
  778. // ....................................................................
  779. /** Add a field to the table. */
  780.  
  781. function addfield($field) {
  782. $this->fields[$field->name] = $field;
  783. }
  784. // ....................................................................
  785. /** Create a new field in the table with given parameters. */
  786.  
  787. function newfield($name, $num, $type, $default="", $notnull=false) {
  788. $ispkey = (in_array($num, $this->pkey));
  789. $this->fields[$name] = new dbfield($this->schema, $name, $num, $type, $default, $notnull, $ispkey);
  790. } // newfield
  791. // ....................................................................
  792. /** Returns field object of given attnum (order number) */
  793.  
  794. function getfieldbynum($num) {
  795. foreach ($this->fields as $field) {
  796. if ($field->num == $num) return $field;
  797. }
  798. return false;
  799. } // getfieldbynum
  800. // ....................................................................
  801. /** Returns field number of given field name */
  802.  
  803. function getfieldnum($fieldname) {
  804. if (isset($this->fields[$fieldname])) {
  805. $field = $this->fields[$fieldname];
  806. return $field->num;
  807. }
  808. else return -1;
  809. }
  810. // ....................................................................
  811. /**
  812. * Returns a candidate label field name according to some fairly simple
  813. * heuristics. This would be a field suitable for displaying in a listbox
  814. * which is somewhat more informative than a keyfield. If nothing is
  815. * found then the key is used as fallback.
  816. * @param $pattern Extra pattern to use in matching likely fieldnames
  817. */
  818. function getlabelfield($pattern="") {
  819. $keyfields = $this->getkeyfieldnames();
  820. $patts = array();
  821. if ($pattern != "") {
  822. $patts[] = $pattern;
  823. }
  824. $patts[] = "name|title|desc|label";
  825. foreach ($patts as $patt) {
  826. foreach ($this->fields as $field) {
  827. if (!in_array($field->name, $keyfields)
  828. && preg_match("/$patt/i", $field->name)) {
  829. $labelfield = $field->name;
  830. $done = true;
  831. break;
  832. }
  833. }
  834. }
  835. // Fall back if necessary..
  836. if ($labelfield == "") {
  837. $labelfield = $keyfields[0];
  838. }
  839. return $labelfield;
  840. } // getlabelfield
  841. // ....................................................................
  842. /** Returns field object of given name */
  843.  
  844. function getfield($name) {
  845. return $this->fields[$name];
  846. } // getfield
  847. // ....................................................................
  848. /** Returns list of names of keyfields as array */
  849.  
  850. function getkeyfieldnames() {
  851. $pks = array();
  852. foreach ($this->fields as $field) {
  853. if ($field->ispkey) {
  854. $pks[] = $field->name;
  855. }
  856. }
  857. return $pks;
  858. } // getkeyfieldnames
  859. // ....................................................................
  860. /** Returns list of names of non-keyfields as array */
  861.  
  862. function getnonkeyfieldnames() {
  863. $npks = array();
  864. foreach ($this->fields as $field) {
  865. if (!$field->ispkey) {
  866. $npks[] = $field->name;
  867. }
  868. }
  869. return $npks;
  870. }
  871. // ....................................................................
  872. /** Dump the table description to stdout. */
  873.  
  874. function dump() {
  875. $s = "\nTable: $this->name\n";
  876. foreach ($this->fields as $field) {
  877. $s .= $field->dump();
  878. }
  879. // Indexes..
  880. foreach ($this->indexes as $indexname => $index) {
  881. $s .= $index->dump();
  882. }
  883. // Constraints..
  884. foreach ($this->constraints as $conname => $con) {
  885. $s .= $con->dump();
  886. }
  887. return $s;
  888. }
  889. // ....................................................................
  890. /** Return the SQL which will create this table. */
  891.  
  892. function create() {
  893. $s = "";
  894. // Table and fields..
  895. $s .= "create table $this->name (\n";
  896. foreach ($this->fields as $field) {
  897. $s .= $field->create() . ",\n";
  898. }
  899. $s = substr($s, 0, -2);
  900. $s .= "\n);\n";
  901. // Indexes..
  902. foreach ($this->indexes as $indexname => $index) {
  903. $s .= $index->create();
  904. }
  905. // Constraints..
  906. foreach ($this->constraints as $conname => $con) {
  907. $s .= $con->create_inline() . "\n";
  908. }
  909. return $s;
  910. }
  911. // ....................................................................
  912. /** Return SQL which will create a column in this table. The $column
  913. * passed in is actually a field object.
  914. */
  915. function addcolumn($column) {
  916. $s = "alter table \"$this->name\" add column";
  917. $s .= $column->create() . "\n";
  918. return $s;
  919. }
  920. // ....................................................................
  921. /** Return SQL to set the default for given field on this table. */
  922.  
  923. function setdefault($column) {
  924. $s = "alter table \"$this->name\" alter column \"$column->name\"";
  925. if ($column->default == "") $s .= " drop default;\n";
  926. else $s .= " set default $column->default;\n";
  927. return $s;
  928. }
  929. // ....................................................................
  930. /** Return SQL to set the NULL/NOT NULL constraint.. */
  931.  
  932. function setnullconstraint($column) {
  933. $s = "alter table \"$this->name\" alter column \"$column->name\"";
  934. if ($column->notnull) $s .= " set not null;\n";
  935. else $s .= " drop not null;\n";
  936. return $s;
  937. }
  938. // ....................................................................
  939. /** Return SQL to drop a column from the table. The $column passed
  940. * is actually a field object.
  941. */
  942. function dropcolumn($column) {
  943. $s = "alter table \"$this->name\" ";
  944. $s .= $column->drop() . "\n";
  945. return $s;
  946. }
  947. // ....................................................................
  948. /** Return the SQL to drop this table. */
  949.  
  950. function drop() {
  951. $s .= "drop table $this->name;\n";
  952. return $s;
  953. }
  954. } // class dbtable
  955. // ----------------------------------------------------------------------
  956.  
  957. /**
  958. * Class describing a database schema. This object hold ALL the information
  959. * for the named database including tables, constraints, functions, triggers
  960. * and sequences. Methods are provided, however to allow you to obtain the
  961. * information for an individual table (@see getschema_table()), rather than
  962. * having to read in the whole schema. For all other info, you must use the
  963. * getschema() method to read all information in, then access it via the
  964. * arrays and methods provided.
  965. *
  966. * @package database
  967. */
  968. class schema extends SchemaObject {
  969. var $database_version = 0;
  970. var $tables = array();
  971. var $sequences = array();
  972. var $constraints = array();
  973. var $indexes = array();
  974. var $functions = array();
  975. var $triggers = array();
  976. // ....................................................................
  977. /**
  978. * Create a schema (database) of given name. The name should be a
  979. * valid existing database name that is currently connected. It will
  980. * be selected to ensure the correct data is obtained.
  981. */
  982. function schema($name) {
  983. $this->name = $name;
  984. $this->getversion();
  985. }
  986. // ....................................................................
  987. /**
  988. * Acquire all of the schema details.
  989. * Override this method for your specific database type.
  990. */
  991. function getschema() {
  992. global $RESPONSE;
  993. if (isset($RESPONSE)) {
  994. $RESPONSE->select_database($this->name);
  995. }
  996. $this->gettables();
  997. $this->gettriggers();
  998. $this->getfunctions();
  999. $this->getsequences();
  1000. } // get
  1001. // ....................................................................
  1002. /** Populates schema tables.
  1003. * Override this method for your specific database type. */
  1004.  
  1005. function gettables() { }
  1006. // ....................................................................
  1007. /** Populates schema triggers.
  1008. * Override this method for your specific database type. */
  1009.  
  1010. function gettriggers() { }
  1011. // ....................................................................
  1012. /** Populates schema sequences.
  1013. * Override this method for your specific database type. */
  1014.  
  1015. function getsequences() { }
  1016. // ....................................................................
  1017. /**
  1018. * Acquire the schema details of a specific database table. This method
  1019. * is provided to cater for the common requirement of acquiring details
  1020. * for a specific table, without having to endure the overhead of reading
  1021. * all of the database schema metadata to get it.
  1022. * Override this method for your specific database type.
  1023. *
  1024. * @param string $tablename Name of the table to acquire schema of
  1025. */
  1026. function getschema_table($tablename) {
  1027. if (!isset($this->tables[$tablename])) {
  1028. $table = new dbtable($this, $tablename, $this->database_version);
  1029. $table->getschema();
  1030. $this->addtable($table);
  1031. }
  1032. } // get
  1033. // ....................................................................
  1034. /**
  1035. * Acquire the database version.
  1036. * Override this method for your specific database type.
  1037. */
  1038. function getversion() {
  1039. $this->database_version = 0;
  1040. }
  1041. // ....................................................................
  1042. /** Set the database version */
  1043.  
  1044. function set_dbversion($ver) {
  1045. $this->database_version = $ver;
  1046. }
  1047. // ....................................................................
  1048. /**
  1049. * Return database capabilities. There are specific capabilities which
  1050. * the diff code needs to query, and this method should be overridden
  1051. * in the specific database module to answer those questions.
  1052. */
  1053. function capable_of($capability="") {
  1054. switch ($capability) {
  1055. // Supports the ALTER <tablename> DROP <colname> SQL
  1056. // statement to remove table columns.
  1057. case "alter_table_drop_column":
  1058. $cando = false;
  1059. break;
  1060. // Supports functions or stored procedures.
  1061. case "stored_procedures":
  1062. $cando = false;
  1063. break;
  1064. // Can define check constraints on table columns.
  1065. case "check_constraints":
  1066. $cando = false;
  1067. break;
  1068. // Can define RI constraints between table/columns to
  1069. // support foreign-keys.
  1070. case "RI_constraints":
  1071. $cando = false;
  1072. break;
  1073. // Supports indexes on table columns.
  1074. case "indexes":
  1075. $cando = false;
  1076. break;
  1077. // Unique indexes are auto-generated with unique constraints. Ie.
  1078. // when a primary key constraint is added to a table a unique
  1079. // index is automatically built for it.
  1080. case "unique_index_with_constraint":
  1081. $cando = false;
  1082. break;
  1083. // Supports triggers on table update, delete, insert.
  1084. case "triggers":
  1085. $cando = false;
  1086. break;
  1087. // Supports named sequences.
  1088. case "named_sequences":
  1089. $cando = false;
  1090. break;
  1091. default:
  1092. $cando = false;
  1093. }
  1094. return $cando;
  1095. }
  1096. // ....................................................................
  1097. /** Add a sequence to the schema information. */
  1098.  
  1099. function addsequence($schemaobj) {
  1100. $schemaobj->schema = $this;
  1101. $this->sequences[$schemaobj->name] = $schemaobj;
  1102. }
  1103. // ....................................................................
  1104. /** Add a table to the schema information. */
  1105.  
  1106. function addtable($schemaobj) {
  1107. $schemaobj->schema = $this;
  1108. $this->tables[$schemaobj->name] = $schemaobj;
  1109. }
  1110. // ....................................................................
  1111. /** Add a constraint to the schema information. */
  1112.  
  1113. function addconstraint($schemaobj) {
  1114. $schemaobj->schema = $this;
  1115. $this->constraints[$schemaobj->name] = $schemaobj;
  1116. }
  1117. // ....................................................................
  1118. /** Add a function to the schema information. */
  1119.  
  1120. function addfunction($schemaobj) {
  1121. $schemaobj->schema = $this;
  1122. $this->functions[$schemaobj->name] = $schemaobj;
  1123. }
  1124. // ....................................................................
  1125. /** Add a trigger to the schema information. */
  1126.  
  1127. function addtrigger($schemaobj) {
  1128. $schemaobj->schema = $this;
  1129. $this->triggers[$schemaobj->name] = $schemaobj;
  1130. }
  1131. // ....................................................................
  1132. /** Returns table object of given name */
  1133.  
  1134. function gettable($name) {
  1135. return $this->tables[$name];
  1136. }
  1137. // ....................................................................
  1138. /** Returns constraint object of given name */
  1139.  
  1140. function getconstraint($name) {
  1141. $gotcon = false;
  1142. if (isset($this->constraints[$name])) {
  1143. $gotcon = $this->constraints[$name];
  1144. }
  1145. else {
  1146. // Search tables next..
  1147. foreach ($this->tables as $table) {
  1148. if (isset($table->constraints[$name])) {
  1149. $gotcon = $table->constraints[$name];
  1150. break;
  1151. }
  1152. }
  1153. }
  1154. return $gotcon;
  1155. }
  1156. // ....................................................................
  1157. /** Returns index object of given name */
  1158.  
  1159. function getindex($name) {
  1160. $gotidx = false;
  1161. if (isset($this->indexes[$name])) {
  1162. $gotidx = $this->indexes[$name];
  1163. }
  1164. else {
  1165. // Search tables next..
  1166. foreach ($this->tables as $table) {
  1167. if (isset($table->indexes[$name])) {
  1168. $gotidx = $table->indexes[$name];
  1169. break;
  1170. }
  1171. }
  1172. }
  1173. return $gotidx;
  1174. }
  1175. // ....................................................................
  1176. /** Returns function object of given name */
  1177.  
  1178. function getfunction($name) {
  1179. return $this->functions[$name];
  1180. }
  1181. // ....................................................................
  1182. /** Returns trigger object of given name */
  1183.  
  1184. function gettrigger($name) {
  1185. return $this->triggers[$name];
  1186. }
  1187. // ....................................................................
  1188. /** Returns seqeuence object of given name */
  1189.  
  1190. function getsequence($name) {
  1191. return $this->sequences[$name];
  1192. }
  1193. // ....................................................................
  1194. /** Returns true if named constraint exists. */
  1195.  
  1196. function constraint_exists($name) {
  1197. return ($this->getconstraint($name) !== false);
  1198. }
  1199. // ....................................................................
  1200. /** Returns true if named index exists. */
  1201.  
  1202. function index_exists($name) {
  1203. return ($this->getindex($name) !== false);
  1204. }
  1205. // ....................................................................
  1206. /** Dump this entire schema description to stdout. */
  1207.  
  1208. function dump() {
  1209. $s = "Database: $this->name\n";
  1210. $s .= "\nTables:\n";
  1211. foreach ($this->tables as $table) {
  1212. $s .= $table->dump();
  1213. }
  1214. $s .= "\nTriggers:\n";
  1215. foreach ($this->triggers as $trigger) {
  1216. $s .= $trigger->dump();
  1217. }
  1218. $s .= "\nFunctions:\n";
  1219. foreach ($this->functions as $func) {
  1220. $s .= $func->dump();
  1221. }
  1222. $s .= "\nSequences:\n";
  1223. foreach ($this->sequences as $seq) {
  1224. $s .= $seq->dump();
  1225. }
  1226. return $s;
  1227. } // dump
  1228.  
  1229. // ....................................................................
  1230. /**
  1231. * Produce the SQL required to morph the schema described in the passed
  1232. * dbschema object $db, into the schema we have in this current object.
  1233. * The resulting SQL is commented. This virtual function is database
  1234. * specific.
  1235. * @param object $schema The schema to morph into the current schema
  1236. * @return string The SQL required to make passed-in schema same as current
  1237. */
  1238. function diff($schema) {
  1239. return "";
  1240. }
  1241. } // class schema
  1242. // ----------------------------------------------------------------------
  1243.  
  1244. ?>

Documentation generated by phpDocumentor 1.3.0RC3