<?php

/**
 *--------------------------------------
 * SQL
 *--------------------------------------
 * @project		: pfa
 * @author		: cblee
 * @created		: 2017-03-29
 * @copyright	: (c)2017 AsThis
 *--------------------------------------
 */
defined('PFA_PATH') or exit('Access Denied');

class Sql {
	// strip the '/* .. */' comments
	public static function remove_comments(&$output) {
		$lines = explode("\n", $output);
		$output = '';

		$lineCount = count($lines);
		$inComment = false;
		for($i = 0; $i < $lineCount; $i++) {
			$_line = $lines[$i];
			if('/*' == substr($_line, 0, 2)) {
				$inComment = true;
			}
			if(!$inComment) {
				$output .= $lines[$i]."\n";
			}
			if('*/' == substr($_line, -2) or '*/;' == substr($_line, -3)) {
				$inComment = false;
			}
		}

		unset($lines);
		return $output;
	}

	// strip the '#' and '--' comment lines
	public static function remove_remarks($sql) {
		$lines = explode("\n", $sql);
		$sql = ''; //for lower mem. use

		$lineCount = count($lines);
		$output = '';

		for($i = 0; $i < $lineCount; $i++) {
			$_line = $lines[$i];
			if('#' == $_line[0] or '--' == substr($_line, 0, 2)) {
				$output .= "\n";
			}
			else {
				$output .= $lines[$i]."\n";
			}
		}

		return $output;
	}

	// split an uploaded sql file into single sql statements.
	public static function split_sql($sql, $delimiter = ';') {
		// Split up our string into "possible" SQL statements.
		$tokens = explode($delimiter, trim($sql));

		$sql = ''; //for lower mem. use
		$output = array();

		// we don't actually care about the matches preg gives us.
		$matches = array();

		// this is faster than calling count($oktens) every time thru the loop.
		$tokenCount = count($tokens);
		for($i = 0; $i < $tokenCount; $i++) {
			// Don't wanna add an empty string as the last thing in the array.
			if(($i != ($tokenCount - 1)) || (strlen($tokens[$i] > 0))) {
				// This is the total number of single quotes in the token.
				$totalQuotes = preg_match_all("/'/", $tokens[$i], $matches);
				// Counts single quotes that are preceded by an odd number of backslashes,
				// which means they're escaped quotes.
				$escapedQuotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$i], $matches);

				$unescapedQuotes = $totalQuotes - $escapedQuotes;

				// If the number of unescaped quotes is even, then the delimiter did NOT occur inside a string literal.
				if(($unescapedQuotes % 2) == 0) {
					// It's a complete sql statement.
					$output[] = $tokens[$i];
					// save memory.
					$tokens[$i] = '';
				}
				else {
					// incomplete sql statement. keep adding tokens until we have a complete one.
					// $temp will hold what we have so far.
					$temp = $tokens[$i].$delimiter;
					// save memory..
					$tokens[$i] = '';

					// Do we have a complete statement yet?
					$completeStmt = false;

					for($j = $i + 1; (!$completeStmt && ($j < $tokenCount)); $j++) {
						// This is the total number of single quotes in the token.
						$totalQuotes = preg_match_all("/'/", $tokens[$j], $matches);
						// Counts single quotes that are preceded by an odd number of backslashes,
						// which means they're escaped quotes.
						$escapedQuotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$j], $matches);

						$unescapedQuotes = $totalQuotes - $escapedQuotes;

						if(($unescapedQuotes % 2) == 1) {
							// odd number of unescaped quotes. In combination with the previous incomplete
							// statement(s), we now have a complete statement. (2 odds always make an even)
							$output[] = $temp.$tokens[$j];

							//for lower mem. use
							$tokens[$j] = '';
							$temp = '';

							// exit the loop.
							$completeStmt = true;
							// make sure the outer loop continues at the right point.
							$i = $j;
						}
						else {
							// even number of unescaped quotes. We still don't have a complete statement.
							// (1 odd and 1 even always make an odd)
							$temp .= $tokens[$j].$delimiter;
							// save memory.
							$tokens[$j] = '';
						}
					}
				}
			}
		}
		return $output;
	}

	public function __construct() {
	}
}

?>