0, 'SCAN' => 1, 'SQL_SCAN' => 2, 'IN_SQL' => 3, 'END_SQL' => 4, 'QUOTE_SCAN' => 5, 'IN_QUOTE' => 6, 'START_COPY' => 7, 'IN_COPY' => 8, 'ERROR' => 9, 'IN_COMMENT' => 10, 'IN_SQL_COMMENT' => 11, 'IN_DOLDOL' => 12, 'DONE' => 999) ; $names = array_flip($states); $state = $states['INIT']; $par_level = 0; $com_level = 0; $doldolstack = array(); $l = ''; $sql = ''; $chunk = ''; $rest = ''; $sql_list = array(); $copy_table = ''; $copy_rest = ''; $copy_data = array(); $copy_data_tmp = array(); $copy_field = ''; while ($state != $states['DONE']) { // error_log("STATE_LOOP: state=$names[$state], l=".RED.$l.NORMAL.", chunk=".RED.$chunk.NORMAL.", rest=".RED.$rest.NORMAL); // error_log(RED."<".GREEN.$sql.RED.">".NORMAL); $matches = array(); switch ($state) { case $states['INIT']: // error_log('INIT'); $l = get_next_line($f); if ($l === false) { $state = $states['DONE']; continue; } $state = $states['SCAN']; break; // End of INIT case $states['SCAN']: // error_log('SCAN'); if (($l == '') || preg_match('/^\s*$/', $l) || preg_match('/^\s*--/', $l)) { $l = get_next_line($f); if ($l === false) { $state = $states['DONE']; continue; } continue; } elseif (preg_match('/\s*copy\s+\"[\w_]+\"\s*(\([\w, "]+\))?\s*from\s+stdin\s*;/i', $l) || preg_match('/\s*copy\s+[\w_]+\s*(\([\w, "]+\))?\s*from\s+stdin\s*;/i', $l)) { $state = $states['START_COPY']; continue; } else { $sql = ''; $state = $states['SQL_SCAN']; continue; } break; // End of SCAN case $states['IN_COMMENT']: // error_log('IN_COMMENT'); if (($l == '') || preg_match('/^\s*$/', $l)) { $l = get_next_line($f); if ($l === false) { error_log("End of file reached during a comment"); $state = $states['ERROR']; continue; } $state = $states['IN_COMMENT']; continue; } elseif (preg_match(',\*/,', $l) || preg_match(',/\*,', $l)) { $l = preg_replace(',.*?((/\*)|(\*/)),', '$1', $l, 1); $chunk = substr($l,0,2); $rest = substr($l,2); if ($chunk == '/*') { $com_level += 1; } else { $com_level -= 1; } if ($com_level == 0) { $state = $states['SQL_SCAN']; continue; } else { $state = $states['IN_COMMENT']; continue; } } else { $l = get_next_line($f); if ($l === false) { error_log("End of file reached during a comment"); $state = $states['ERROR']; continue; } $state = $states['IN_COMMENT']; continue; } break; // End of IN_COMMENT case $states['IN_SQL_COMMENT']: // error_log('IN_SQL_COMMENT'); if (($rest == '') || preg_match('/^\s*$/')) { $rest = get_next_line($f); if ($rest === false) { error_log("End of file reached during a comment"); $state = $states['ERROR']; continue; } $state = $states['IN_SQL_COMMENT']; continue; } elseif (preg_match(',\*/,', $rest) || preg_match(',/\*,', $rest)) { $rest = preg_replace(',.*?((/\*)|(\*/)),', '$1', $l, 1); $chunk = substr($rest,0,2); $rest = substr($rest,2); if ($chunk == '/*') { $com_level += 1; } else { $com_level -= 1; } if ($com_level == 0) { $state = $states['IN_SQL']; continue; } else { $state = $states['IN_SQL_COMMENT']; continue; } } else { $rest = get_next_line($f); if ($rest === false) { error_log("End of file reached during a comment"); $state = $states['ERROR']; continue; } $state = $states['IN_SQL_COMMENT']; continue; } break; // End of IN_SQL_COMMENT case $states['SQL_SCAN']: // error_log('SQL_SCAN'); if (($l == '') || preg_match('/^\s*$/', $l) || preg_match('/^--/', $l)) { $l = get_next_line($f); if ($l === false) { error_log("End of file reached during an SQL statement"); $state = $states['ERROR']; continue; } $state = $states['SQL_SCAN']; continue; } elseif (preg_match(',^\s*/\*,', $l)) { $l = preg_replace(',^\s*/\*,','',$l, 1); $com_level = 1; $state = $states['IN_COMMENT']; continue; } elseif (preg_match(',^(.*?)\$([\w]*)\$,', $l, $matches)) { $sql .= $matches[1].'$'.$matches[2].'$'; array_push($doldolstack,$matches[2]); $l = preg_replace(',^(.*?)\$[\w]*\$,','',$l, 1); $state = $states['IN_DOLDOL']; continue; } else { preg_match(',^([^()\';-]*)(.*),', $l, $matches); $chunk = $matches[1]; $rest = $matches[2]; $sql .= $chunk; $state = $states['IN_SQL']; continue; } break; // End of SQL_SCAN case $states['IN_SQL']: // error_log('IN_SQL'); if (preg_match(',^\s*/\*,',$rest)) { $rest = preg_replace(',^\s*/\*,','',$rest, 1); $com_level = 1; $state = $states['IN_SQL_COMMENT']; continue; } elseif (preg_match('/^\(/', $rest)) { $par_level += 1; $sql .= '('; $rest = substr($rest, 1); $l = $rest; $state = $states['SQL_SCAN']; continue; } elseif (preg_match('/^\)/', $rest) && $par_level > 0) { $par_level -= 1; $sql .= ')'; $rest = substr($rest, 1); $l = $rest; $state = $states['SQL_SCAN']; continue; } elseif (preg_match('/^\)/', $rest)) { error_log("Detected ')' without any matching '('"); $state = $states['ERROR']; continue; } elseif (preg_match('/^--/', $rest)) { $rest = ''; $l = $rest; $state = $states['SQL_SCAN']; continue; } elseif (preg_match('/^-/', $rest)) { $sql .= '-'; $rest = substr($rest, 1); $l = $rest; $state = $states['SQL_SCAN']; continue; } elseif (preg_match('/^;/', $rest) && ($par_level == 0)) { $sql .= ';'; $rest = substr($rest, 1); $state = $states['END_SQL']; continue; } elseif (preg_match('/^;/', $rest)) { error_log("Detected ';' within a parenthesis"); $state = $states['ERROR']; continue; } elseif ($rest == '') { $l = $rest; $sql .= ' '; $state = $states['SQL_SCAN']; continue; } elseif (preg_match("/^\\'/", $rest)) { $oldrest = $rest; $sql .= "'"; $rest = substr($rest, 1); $l = $rest; $state = $states['IN_QUOTE']; continue; } else { error_log("Unknown event in IN_SQL state"); $state = $states['ERROR']; continue; } break; // End of IN_SQL case $states['END_SQL']: // error_log('END_SQL'); if (preg_match('/^\s*$/', $sql)) { $sql = ''; $l = $rest; $state = $states['SCAN']; continue; } else { array_push($sql_list, $sql); // error_log(RED."---->".$sql.NORMAL); $sql = ''; $l = $rest; $state = $states['SCAN']; continue; } break; // End of END_SQL case $states['QUOTE_SCAN']: // error_log('QUOTE_SCAN'); if ($rest == '') { $sql .= "\n"; $l = get_next_line($f); if ($l === false) { error_log("End of file reached during a quoted string"); $state = $states['ERROR']; continue; } $rest = $l; $state = $states['QUOTE_SCAN']; continue; } else { preg_match("/^([^\\\']*)(.*)/", $l, $matches); $chunk = $matches[1]; $rest = $matches[2]; $sql .= $chunk; $state = $states['IN_QUOTE']; continue; } break; // End of QUOTE_SCAN case $states['IN_QUOTE']: // error_log('IN_QUOTE'); if (preg_match("/^'/", $rest)) { $sql .= "'"; $rest = substr($rest, 1); $l = $rest; $state = $states['SQL_SCAN']; continue; } elseif (preg_match("/^\\\'/", $rest)) { $sql .= "''"; $rest = substr($rest, 2); $state = $states['IN_QUOTE']; continue; } elseif (preg_match("/^\\\[^\\\]/", $rest)) { $sql .= '\\'; $rest = substr($rest, 1); $state = $states['IN_QUOTE']; continue; } elseif (preg_match('/^\\\$/', $rest)) { $sql .= "\n"; $rest = substr($rest, 1); $state = $states['IN_QUOTE']; continue; } else { $l = $rest; $state = $states['QUOTE_SCAN']; continue; } break; // End of IN_QUOTE case $states['IN_DOLDOL']: // error_log('IN_DOLDOL'); $cur = $doldolstack[0]; if (preg_match(",^(.*?)\\$([\w]*)\\$,", $l, $matches)) { $sql .= $matches[1].'$'.$matches[2].'$'; $found = $matches[2]; if ($found == $cur) { array_pop($doldolstack); if (count($doldolstack) > 0) { $state = $states['IN_DOLDOL']; continue; } else { $rest = preg_replace(",^.*?\\$[\w]*\\$,",'',$l, 1); $l = preg_replace(",^.*?\\\$[\w]*\\\$,",'',$l,1); $state = $states['SQL_SCAN']; continue; } } else { array_push($doldolstack, $found); $state = $states['IN_DOLDOL']; continue; } $l = preg_replace(",^.*?\\\$[\w]*\\\$,",'',$l,1); $state = $states['IN_DOLDOL']; continue; } else { $sql .= $l."\n"; $l = get_next_line($f); if ($l === false) { error_log("End of file reached during a dollar-quoted string"); $state = $states['ERROR']; continue; } $state = $states['IN_DOLDOL']; continue; } break; // End of IN_DOLDOL case $states['START_COPY']: // error_log('START_COPY'); if (preg_match('/\s*copy\s+\"([\w_]+)\"\s*(\\([\w, "]+\\))?\s*from\s+stdin\s*;(.*)/i', $l, $matches)) { $copy_table = $matches[1]; $copy_field_list = trim($matches[2]); if ($copy_field_list != '') { $copy_field_list = ' '.$copy_field_list; } $copy_rest = $matches[3]; $l = get_next_line($f); if ($l === false) { error_log("End of file reached during a COPY statement"); $state = $states['ERROR']; continue; } $state = $states['IN_COPY']; continue; } elseif (preg_match('/\s*copy\s+([\w_]+)\s*(\\([\w, "]+\\))?\s*from\s+stdin\s*;(.*)/i', $l, $matches)) { $copy_table = $matches[1]; $copy_field_list = trim($matches[2]); if ($copy_field_list != '') { $copy_field_list = ' '.$copy_field_list; } $copy_rest = $matches[3]; $l = get_next_line($f); if ($l === false) { error_log("End of file reached during a COPY statement"); $state = $states['ERROR']; continue; } $state = $states['IN_COPY']; continue; } else { error_log("Unknown event in START_COPY state"); continue; } break; // End of START_COPY case $states['IN_COPY']: // error_log('IN_COPY'); if ($l == '\.') { $l = $copy_rest; $state = $states['SCAN']; continue; } else { $copy_data = array(); $copy_data_tmp = explode ("\t", $l); foreach ($copy_data_tmp as $copy_field) { if ($copy_field == '\N') { $copy_field = 'NULL'; } else { $copy_field = preg_replace('/\'/','\'\'', $copy_field); $copy_field = "'".$copy_field."'"; } array_push($copy_data, $copy_field); } $sql = "INSERT INTO \"$copy_table\"$copy_field_list VALUES ("; $sql .= implode (', ', $copy_data); $sql .= ")"; array_push($sql_list, $sql); // error_log(RED."---->".$sql.NORMAL); $l = get_next_line($f); if ($l === false) { error_log("End of file reached during a COPY statement"); $state = $states['ERROR']; continue; } $state = $states['IN_COPY']; continue; } break; // End of IN_COPY case $states['DONE']: // error_log('DONE'); // We're done. break; // End of DONE case $states['ERROR']: // error_log('ERROR'); error_log("Reached the ERROR state, dying. State machine is buggy."); exit (1); break; // End of ERROR default: error_log("State machine went to an unknown state, redirecting to ERROR"); $state = $states['ERROR']; break; } // error_log("State=$names[$state] after switch"); } fclose($f); return $sql_list; } // Local Variables: // mode: php // c-file-style: "bsd" // End: ?>