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.
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 $
20 /** @var $driver string The database driver */
23 /** @var $dataSource object The database connection object */
26 /** @var $debug boolean Enable debugging (print SQL statements as they are executed) */
29 /** @var $errorMsg string Error message */
32 /** @var $commentDelim string Delimiter for SQL comments used by the data source */
35 /** @var $statementDelim string Delimiter for SQL statements used by the data source */
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
= ';';
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!");
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++
) {
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());
82 // Abort if fail on error is enabled
90 return isset($error) ?
false : true;
94 * Strip SQL comments from 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.
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;
132 // The statement is not complete, the delimiter must be inside the statement
133 $currentStatement .= $this->statementDelim
;
141 * Return the last error message that occurred in parsing.
144 function getErrorMsg() {
145 return count($this->errorMsg
) == 0 ?
null : array_pop($this->errorMsg
);