Passed
Push — master ( eabf33...342b63 )
by Michiel
05:53
created

DefaultPDOQuerySplitter   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Test Coverage

Coverage 97.92%

Importance

Changes 0
Metric Value
eloc 49
c 0
b 0
f 0
dl 0
loc 122
ccs 47
cts 48
cp 0.9792
rs 10
wmc 20

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
D nextQuery() 0 84 19
1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 *
19
 * @package phing.tasks.ext.pdo
20
 */
21
22
use Phing\Io\Reader;
23
use Phing\Util\StringHelper;
24
25
/**
26
 * Splits SQL source into queries using simple regular expressions
27
 *
28
 * Extracted from PDOSQLExecTask::runStatements()
29
 *
30
 * @author  Hans Lellelid <[email protected]>
31
 * @author  Alexey Borzov <[email protected]>
32
 * @package phing.tasks.ext.pdo
33
 */
34
class DefaultPDOQuerySplitter extends PDOQuerySplitter
35
{
36
    /**
37
     * Delimiter type, one of PDOSQLExecTask::DELIM_ROW or PDOSQLExecTask::DELIM_NORMAL
38
     *
39
     * @var string
40
     */
41
    private $delimiterType;
42
43
    /**
44
     * Leftover SQL from previous line
45
     *
46
     * @var string
47
     */
48
    private $sqlBacklog = '';
49
50
    /**
51
     * Constructor, sets the parent task, reader with SQL source and delimiter type
52
     *
53
     * @param PDOSQLExecTask $parent
54
     * @param Reader $reader
55
     * @param string $delimiterType
56
     */
57 2
    public function __construct(PDOSQLExecTask $parent, Reader $reader, $delimiterType = PDOSQLExecTask::DELIM_NORMAL)
58
    {
59 2
        parent::__construct($parent, $reader);
60 2
        $this->delimiterType = $delimiterType;
61 2
    }
62
63
    /**
64
     * Returns next query from SQL source, null if no more queries left
65
     *
66
     * In case of "row" delimiter type this searches for strings containing only
67
     * delimiters. In case of "normal" delimiter type, this uses simple regular
68
     * expression logic to search for delimiters.
69
     *
70
     * @return string|null
71
     */
72 2
    public function nextQuery()
73
    {
74 2
        $sql = "";
75 2
        $hasQuery = false;
76
77 2
        while (($line = $this->sqlReader->readLine()) !== null) {
78 2
            $delimiter = $this->parent->getDelimiter();
79 2
            $project = $this->parent->getOwningTarget()->getProject();
80 2
            $line = $project->replaceProperties(trim($line));
81
82
            if (
83 2
                ($line != $delimiter)
84 2
                && (StringHelper::startsWith("//", $line)
85 2
                    || StringHelper::startsWith("--", $line)
86 2
                    || StringHelper::startsWith("#", $line))
87
            ) {
88 2
                continue;
89
            }
90
91
            if (
92 2
                strlen($line) > 4
93 2
                && strtoupper(substr($line, 0, 4)) == "REM "
94
            ) {
95
                continue;
96
            }
97
98
            // MySQL supports defining new delimiters
99 2
            if (preg_match('/DELIMITER [\'"]?([^\'" $]+)[\'"]?/i', $line, $matches)) {
100 1
                $this->parent->setDelimiter($matches[1]);
101 1
                continue;
102
            }
103
104 2
            if ($this->sqlBacklog !== "") {
105 1
                $sql = $this->sqlBacklog;
106 1
                $this->sqlBacklog = "";
107
            }
108
109 2
            $sql .= " " . $line . "\n";
110
111
            // SQL defines "--" as a comment to EOL
112
            // and in Oracle it may contain a hint
113
            // so we cannot just remove it, instead we must end it
114 2
            if (strpos($line, "--") !== false) {
115 2
                $sql .= "\n";
116
            }
117
118
            // DELIM_ROW doesn't need this (as far as i can tell)
119 2
            if ($this->delimiterType == PDOSQLExecTask::DELIM_NORMAL) {
120 1
                $reg = "#((?:\"(?:\\\\.|[^\"])*\"?)+|'(?:\\\\.|[^'])*'?|" . preg_quote($delimiter) . ")#";
121
122 1
                $sqlParts = preg_split($reg, $sql, 0, PREG_SPLIT_DELIM_CAPTURE);
123 1
                $this->sqlBacklog = "";
124 1
                foreach ($sqlParts as $sqlPart) {
125
                    // we always want to append, even if it's a delim (which will be stripped off later)
126 1
                    $this->sqlBacklog .= $sqlPart;
127
128
                    // we found a single (not enclosed by ' or ") delimiter, so we can use all stuff before the delim as the actual query
129 1
                    if ($sqlPart === $delimiter) {
130 1
                        $sql = $this->sqlBacklog;
131 1
                        $this->sqlBacklog = "";
132 1
                        $hasQuery = true;
133
                    }
134
                }
135
            }
136
137 2
            if ($hasQuery || ($this->delimiterType == PDOSQLExecTask::DELIM_ROW && $line == $delimiter)) {
138
                // this assumes there is always a delimter on the end of the SQL statement.
139 2
                $sql = StringHelper::substring(
140 2
                    $sql,
141 2
                    0,
142 2
                    strlen($sql) - strlen($delimiter)
143 2
                    - ($this->delimiterType == PDOSQLExecTask::DELIM_ROW ? 2 : 1)
144
                );
145
146 2
                return $sql;
147
            }
148
        }
149
150
        // Catch any statements not followed by ;
151 2
        if ($sql !== "") {
152 2
            return $sql;
153
        }
154
155 2
        return null;
156
    }
157
}
158