Translated using Weblate.
[phpmyadmin.git] / libraries / import / sql.php
blob3f1ed8efc2af30da130f9713fdbe11a9b2cc76cc
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * SQL import plugin for phpMyAdmin
6 * @package PhpMyAdmin-Import
7 * @subpackage SQL
8 */
9 if (! defined('PHPMYADMIN')) {
10 exit;
13 /**
16 if (isset($plugin_list)) {
17 $plugin_list['sql'] = array(
18 'text' => __('SQL'),
19 'extension' => 'sql',
20 'options_text' => __('Options'),
22 $compats = PMA_DBI_getCompatibilities();
23 if (count($compats) > 0) {
24 $values = array();
25 foreach ($compats as $val) {
26 $values[$val] = $val;
28 $plugin_list['sql']['options'] = array(
29 array('type' => 'begin_group', 'name' => 'general_opts'),
30 array(
31 'type' => 'select',
32 'name' => 'compatibility',
33 'text' => __('SQL compatibility mode:'),
34 'values' => $values,
35 'doc' => array(
36 'manual_MySQL_Database_Administration',
37 'Server_SQL_mode',
40 array(
41 'type' => 'bool',
42 'name' => 'no_auto_value_on_zero',
43 'text' => __('Do not use <code>AUTO_INCREMENT</code> for zero values'),
44 'doc' => array(
45 'manual_MySQL_Database_Administration',
46 'Server_SQL_mode',
47 'sqlmode_no_auto_value_on_zero'
51 array('type' => 'end_group'),
55 /* We do not define function when plugin is just queried for information above */
56 return;
59 $buffer = '';
60 // Defaults for parser
61 $sql = '';
62 $start_pos = 0;
63 $i = 0;
64 $len= 0;
65 $big_value = 2147483647;
66 $delimiter_keyword = 'DELIMITER '; // include the space because it's mandatory
67 $length_of_delimiter_keyword = strlen($delimiter_keyword);
69 if (isset($_POST['sql_delimiter'])) {
70 $sql_delimiter = $_POST['sql_delimiter'];
71 } else {
72 $sql_delimiter = ';';
75 // Handle compatibility options
76 $sql_modes = array();
77 if (isset($_REQUEST['sql_compatibility']) && 'NONE' != $_REQUEST['sql_compatibility']) {
78 $sql_modes[] = $_REQUEST['sql_compatibility'];
80 if (isset($_REQUEST['sql_no_auto_value_on_zero'])) {
81 $sql_modes[] = 'NO_AUTO_VALUE_ON_ZERO';
83 if (count($sql_modes) > 0) {
84 PMA_DBI_try_query('SET SQL_MODE="' . implode(',', $sql_modes) . '"');
86 unset($sql_modes);
88 /**
89 * will be set in PMA_importGetNextChunk()
91 * @global boolean $GLOBALS['finished']
93 $GLOBALS['finished'] = false;
95 while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) {
96 $data = PMA_importGetNextChunk();
97 if ($data === false) {
98 // subtract data we didn't handle yet and stop processing
99 $offset -= strlen($buffer);
100 break;
101 } elseif ($data === true) {
102 // Handle rest of buffer
103 } else {
104 // Append new data to buffer
105 $buffer .= $data;
106 // free memory
107 unset($data);
108 // Do not parse string when we're not at the end and don't have ; inside
109 if ((strpos($buffer, $sql_delimiter, $i) === false) && !$GLOBALS['finished']) {
110 continue;
113 // Current length of our buffer
114 $len = strlen($buffer);
116 // Grab some SQL queries out of it
117 while ($i < $len) {
118 $found_delimiter = false;
119 // Find first interesting character
120 $old_i = $i;
121 // this is about 7 times faster that looking for each sequence i
122 // one by one with strpos()
123 if (preg_match('/(\'|"|#|-- |\/\*|`|(?i)(?<![A-Z0-9_])' . $delimiter_keyword . ')/', $buffer, $matches, PREG_OFFSET_CAPTURE, $i)) {
124 // in $matches, index 0 contains the match for the complete
125 // expression but we don't use it
126 $first_position = $matches[1][1];
127 } else {
128 $first_position = $big_value;
131 * @todo we should not look for a delimiter that might be
132 * inside quotes (or even double-quotes)
134 // the cost of doing this one with preg_match() would be too high
135 $first_sql_delimiter = strpos($buffer, $sql_delimiter, $i);
136 if ($first_sql_delimiter === false) {
137 $first_sql_delimiter = $big_value;
138 } else {
139 $found_delimiter = true;
142 // set $i to the position of the first quote, comment.start or delimiter found
143 $i = min($first_position, $first_sql_delimiter);
145 if ($i == $big_value) {
146 // none of the above was found in the string
148 $i = $old_i;
149 if (!$GLOBALS['finished']) {
150 break;
152 // at the end there might be some whitespace...
153 if (trim($buffer) == '') {
154 $buffer = '';
155 $len = 0;
156 break;
158 // We hit end of query, go there!
159 $i = strlen($buffer) - 1;
162 // Grab current character
163 $ch = $buffer[$i];
165 // Quotes
166 if (strpos('\'"`', $ch) !== false) {
167 $quote = $ch;
168 $endq = false;
169 while (!$endq) {
170 // Find next quote
171 $pos = strpos($buffer, $quote, $i + 1);
173 * Behave same as MySQL and accept end of query as end of backtick.
174 * I know this is sick, but MySQL behaves like this:
176 * SELECT * FROM `table
178 * is treated like
180 * SELECT * FROM `table`
182 if ($pos === false && $quote == '`' && $found_delimiter) {
183 $pos = $first_sql_delimiter - 1;
184 // No quote? Too short string
185 } elseif ($pos === false) {
186 // We hit end of string => unclosed quote, but we handle it as end of query
187 if ($GLOBALS['finished']) {
188 $endq = true;
189 $i = $len - 1;
191 $found_delimiter = false;
192 break;
194 // Was not the quote escaped?
195 $j = $pos - 1;
196 while ($buffer[$j] == '\\') $j--;
197 // Even count means it was not escaped
198 $endq = (((($pos - 1) - $j) % 2) == 0);
199 // Skip the string
200 $i = $pos;
202 if ($first_sql_delimiter < $pos) {
203 $found_delimiter = false;
206 if (!$endq) {
207 break;
209 $i++;
210 // Aren't we at the end?
211 if ($GLOBALS['finished'] && $i == $len) {
212 $i--;
213 } else {
214 continue;
218 // Not enough data to decide
219 if ((($i == ($len - 1) && ($ch == '-' || $ch == '/'))
220 || ($i == ($len - 2) && (($ch == '-' && $buffer[$i + 1] == '-')
221 || ($ch == '/' && $buffer[$i + 1] == '*')))) && !$GLOBALS['finished']) {
222 break;
225 // Comments
226 if ($ch == '#'
227 || ($i < ($len - 1) && $ch == '-' && $buffer[$i + 1] == '-'
228 && (($i < ($len - 2) && $buffer[$i + 2] <= ' ')
229 || ($i == ($len - 1) && $GLOBALS['finished'])))
230 || ($i < ($len - 1) && $ch == '/' && $buffer[$i + 1] == '*')
232 // Copy current string to SQL
233 if ($start_pos != $i) {
234 $sql .= substr($buffer, $start_pos, $i - $start_pos);
236 // Skip the rest
237 $start_of_comment = $i;
238 // do not use PHP_EOL here instead of "\n", because the export
239 // file might have been produced on a different system
240 $i = strpos($buffer, $ch == '/' ? '*/' : "\n", $i);
241 // didn't we hit end of string?
242 if ($i === false) {
243 if ($GLOBALS['finished']) {
244 $i = $len - 1;
245 } else {
246 break;
249 // Skip *
250 if ($ch == '/') {
251 $i++;
253 // Skip last char
254 $i++;
255 // We need to send the comment part in case we are defining
256 // a procedure or function and comments in it are valuable
257 $sql .= substr($buffer, $start_of_comment, $i - $start_of_comment);
258 // Next query part will start here
259 $start_pos = $i;
260 // Aren't we at the end?
261 if ($i == $len) {
262 $i--;
263 } else {
264 continue;
267 // Change delimiter, if redefined, and skip it (don't send to server!)
268 if (strtoupper(substr($buffer, $i, $length_of_delimiter_keyword)) == $delimiter_keyword
269 && ($i + $length_of_delimiter_keyword < $len)) {
270 // look for EOL on the character immediately after 'DELIMITER '
271 // (see previous comment about PHP_EOL)
272 $new_line_pos = strpos($buffer, "\n", $i + $length_of_delimiter_keyword);
273 // it might happen that there is no EOL
274 if (false === $new_line_pos) {
275 $new_line_pos = $len;
277 $sql_delimiter = substr($buffer, $i + $length_of_delimiter_keyword, $new_line_pos - $i - $length_of_delimiter_keyword);
278 $i = $new_line_pos + 1;
279 // Next query part will start here
280 $start_pos = $i;
281 continue;
284 // End of SQL
285 if ($found_delimiter || ($GLOBALS['finished'] && ($i == $len - 1))) {
286 $tmp_sql = $sql;
287 if ($start_pos < $len) {
288 $length_to_grab = $i - $start_pos;
290 if (! $found_delimiter) {
291 $length_to_grab++;
293 $tmp_sql .= substr($buffer, $start_pos, $length_to_grab);
294 unset($length_to_grab);
296 // Do not try to execute empty SQL
297 if (! preg_match('/^([\s]*;)*$/', trim($tmp_sql))) {
298 $sql = $tmp_sql;
299 PMA_importRunQuery($sql, substr($buffer, 0, $i + strlen($sql_delimiter)));
300 $buffer = substr($buffer, $i + strlen($sql_delimiter));
301 // Reset parser:
302 $len = strlen($buffer);
303 $sql = '';
304 $i = 0;
305 $start_pos = 0;
306 // Any chance we will get a complete query?
307 //if ((strpos($buffer, ';') === false) && !$GLOBALS['finished']) {
308 if ((strpos($buffer, $sql_delimiter) === false) && !$GLOBALS['finished']) {
309 break;
311 } else {
312 $i++;
313 $start_pos = $i;
316 } // End of parser loop
317 } // End of import loop
318 // Commit any possible data in buffers
319 PMA_importRunQuery('', substr($buffer, 0, $len));
320 PMA_importRunQuery();