command->error("SQL file not found at: {$sqlPath}"); return; } $this->command->info("Starting initial data import from: {$sqlPath}"); // Disable foreign key checks for PostgreSQL if (DB::getDriverName() === 'pgsql') { DB::statement("SET session_replication_role = 'replica';"); } else { Schema::disableForeignKeyConstraints(); } $handle = fopen($sqlPath, "r"); if ($handle) { $currentTable = null; $insertCount = 0; $tableColumnMap = []; while (($line = fgets($handle)) !== false) { $line = trim($line); // Detect CREATE TABLE statement to extract column order if (preg_match('/^CREATE TABLE `(.+?)`/i', $line, $matches)) { $currentTable = $matches[1]; $tableColumnMap[$currentTable] = []; continue; } // If we are inside a CREATE TABLE block, look for column definitions if ($currentTable && preg_match('/^\s*`(.+?)`/i', $line, $colMatches)) { $tableColumnMap[$currentTable][] = $colMatches[1]; } // End of CREATE TABLE block if ($currentTable && strpos($line, ') ENGINE') !== false) { $currentTable = null; } // Detect INSERT INTO statement if (preg_match('/^INSERT INTO `(.+?)` VALUES\s*\((.*)\);$/i', $line, $matches)) { $tableName = $matches[1]; $valuesStr = $matches[2]; $values = $this->parseValues($valuesStr); $sqlColumns = $tableColumnMap[$tableName] ?? []; try { $data = $this->mapValuesToTable($tableName, $values, $sqlColumns); if (!empty($data)) { DB::table($tableName)->insert($data); $insertCount++; if ($insertCount % 100 === 0) { $this->command->info("Imported {$insertCount} records..."); } } } catch (\Exception $e) { $this->command->error("Error inserting into {$tableName}: " . $e->getMessage()); } } } fclose($handle); $this->command->info("Finished! Total records imported: {$insertCount}"); } // Re-enable foreign key checks if (DB::getDriverName() === 'pgsql') { DB::statement("SET session_replication_role = 'origin';"); // Update sequences for PostgreSQL $this->updatePostgresSequences(); } Schema::enableForeignKeyConstraints(); } /** * Update PostgreSQL sequences so they don't clash with imported IDs. */ private function updatePostgresSequences() { $this->command->info("Updating PostgreSQL sequences..."); $tables = DB::select("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"); foreach ($tables as $table) { $tableName = $table->table_name; try { $maxId = DB::table($tableName)->max('id'); if ($maxId) { $seqName = "{$tableName}_id_seq"; // Check if sequence exists $seqExists = DB::select("SELECT 1 FROM pg_class WHERE relname = ?", [$seqName]); if ($seqExists) { DB::statement("SELECT setval(?, ?, true)", [$seqName, $maxId]); } } } catch (\Exception $e) { // Ignore if table doesn't have id column or sequence } } } /** * Basic parser for MySQL values string: (val1, val2, ...) */ private function parseValues($str) { $values = []; $i = 0; $len = strlen($str); $current = ''; $inString = false; $stringChar = ''; while ($i < $len) { $char = $str[$i]; if ($inString) { if ($char === $stringChar && ($i === 0 || $str[$i - 1] !== '\\')) { $inString = false; $values[] = str_replace(['\\\'', '\\"'], ["'", '"'], $current); $current = ''; } else { $current .= $char; } } else { if ($char === "'" || $char === '"') { $inString = true; $stringChar = $char; } elseif ($char === ',') { $val = trim($current); if ($val !== '') { $values[] = $this->castValue($val); } $current = ''; } else { $current .= $char; } } $i++; } // Last value $val = trim($current); if ($val !== '') { $values[] = $this->castValue($val); } return $values; } private function castValue($val) { if (strtoupper($val) === 'NULL') return null; if (is_numeric($val) && (strpos($val, '0') !== 0 || $val === '0')) { return $val + 0; // Convert to int or float } return trim($val, "'\""); } /** * Map numerical values to column names based on SQL dump schema and filter by DB schema. */ private function mapValuesToTable($table, $values, $sqlColumns) { if (empty($sqlColumns) || count($sqlColumns) !== count($values)) { return []; // Can't reliably map } // Combine using SQL column names $mapped = array_combine($sqlColumns, $values); // Get actual columns in the database static $dbColumnsCache = []; if (!isset($dbColumnsCache[$table])) { $dbColumnsCache[$table] = DB::getSchemaBuilder()->getColumnListing($table); } $dbColumns = $dbColumnsCache[$table]; // Filter out columns that don't exist in the current DB return array_intersect_key($mapped, array_flip($dbColumns)); } }