baseline
[omp.pkp.sfu.ca.git] / lib / pkp / classes / db / SQLParser.inc.php
blob8206c02dff05b47b1a1d90b1dafacbbfad1a5402
1 <?php
3 /**
4 * @file classes/db/SQLParser.inc.php
6 * Copyright (c) 2000-2009 John Willinsky
7 * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
9 * @class SQLParser
10 * @ingroup db
12 * @brief Class for parsing and executing statements in SQL files.
15 // $Id: SQLParser.inc.php,v 1.3 2009/04/08 21:34:54 asmecher Exp $
18 class SQLParser {
20 /** @var $driver string The database driver */
21 var $driver;
23 /** @var $dataSource object The database connection object */
24 var $dataSource;
26 /** @var $debug boolean Enable debugging (print SQL statements as they are executed) */
27 var $debug;
29 /** @var $errorMsg string Error message */
30 var $errorMsg;
32 /** @var $commentDelim string Delimiter for SQL comments used by the data source */
33 var $commentDelim;
35 /** @var $statementDelim string Delimiter for SQL statements used by the data source */
36 var $statementDelim;
38 /**
39 * Constructor.
40 * @param $driver string the database driver (currently only "mysql" is supported)
41 * @param $debug boolean echo each statement as it's executed
43 function SQLParser($driver, &$dataSource, $debug = false) {
44 $this->driver = $driver;
45 $this->dataSource =& $dataSource;
46 $this->debug = $debug;
47 $this->errorMsg = array();
48 $this->commentDelim = '(\-\-|#)';
49 $this->statementDelim = ';';
52 /**
53 * Parse an SQL file and execute all SQL statements in it.
54 * @param $file string full path to the file
55 * @param $failOnError boolean stop execution if an error is encountered
56 * @return boolean true if no errors occurred, false otherwise
58 function executeFile($file, $failOnError = true) {
59 if (!file_exists($file) || !is_readable($file)) {
60 array_push($this->errorMsg, "$file does not exist or is not readble!");
61 return false;
64 // Read file and break up into SQL statements
65 $sql = join('', file($file));
66 $this->stripComments($sql);
67 $statements =& $this->parseStatements($sql);
69 // Execute each SQL statement
70 for ($i=0, $count=count($statements); $i < $count; $i++) {
71 if ($this->debug) {
72 echo 'Executing: ', $statements[$i], "\n\n";
75 $this->dataSource->execute($statements[$i]);
77 if ($this->dataSource->errorNo() != 0) {
78 // An error occurred executing the statement
79 array_push($this->errorMsg, $this->dataSource->errorMsg());
81 if ($failOnError) {
82 // Abort if fail on error is enabled
83 return false;
84 } else {
85 $error = true;
90 return isset($error) ? false : true;
93 /**
94 * Strip SQL comments from SQL string.
95 * @param $sql string
97 function stripComments(&$sql) {
98 $sql = trim(String::regexp_replace(sprintf('/^\s*%s(.*)$/m', $this->commentDelim), '', $sql));
102 * Parse SQL content into individual SQL statements.
103 * @param $sql string
104 * @return array
106 function &parseStatements(&$sql) {
107 $statements = array();
108 $statementsTmp = explode($this->statementDelim, $sql);
110 $currentStatement = '';
111 $numSingleQuotes = $numEscapedSingleQuotes = 0;
113 // This method for parsing the SQL statements was adapted from one used in phpBB (http://www.phpbb.com/)
114 for ($i=0, $count=count($statementsTmp); $i < $count; $i++) {
115 // Get total number of single quotes in string
116 $numSingleQuotes += String::substr_count($statementsTmp[$i], "'");
118 // Get number of escaped single quotes
119 $numEscapedSingleQuotes += String::regexp_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $statementsTmp[$i], $matches);
121 $currentStatement .= $statementsTmp[$i];
123 if (($numSingleQuotes - $numEscapedSingleQuotes) % 2 == 0) {
124 // Even number of unescaped single quotes, so statement must be complete
125 if (trim($currentStatement) !== '') {
126 array_push($statements, trim($currentStatement));
128 $currentStatement = '';
129 $numSingleQuotes = $numEscapedSingleQuotes = 0;
131 } else {
132 // The statement is not complete, the delimiter must be inside the statement
133 $currentStatement .= $this->statementDelim;
137 return $statements;
141 * Return the last error message that occurred in parsing.
142 * @return string
144 function getErrorMsg() {
145 return count($this->errorMsg) == 0 ? null : array_pop($this->errorMsg);