mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 12:05:51 -04:00
Add /server backup lite, which backups everything except blockdb and undo files.
This commit is contained in:
parent
dcece84ad1
commit
2bc639abd8
@ -85,7 +85,7 @@ namespace MCGalaxy.Commands {
|
||||
// This means all folders, and files in these folders.
|
||||
Player.Message(p, "Server backup (Everything) started. Please wait while backup finishes.");
|
||||
Save(true, true, p);
|
||||
} else if (type == "db") {
|
||||
} else if (type == "database" || type == "sql" || type == "db") {
|
||||
// Backup database only.
|
||||
// Create SQL statements for this. The SQL will assume the settings for the current configuration are correct.
|
||||
// This means we use the currently defined port, database, user, password, and pooling.
|
||||
@ -94,12 +94,15 @@ namespace MCGalaxy.Commands {
|
||||
// This means all folders, and files in these folders.
|
||||
Player.Message(p, "Server backup (Database) started. Please wait while backup finishes.");
|
||||
Save(false, true, p);
|
||||
} else if (type == "allbutdb") {
|
||||
} else if (type == "allbutdb" || type == "files" || type == "file") {
|
||||
// Important to save everything to a .zip file (Though we can rename the extention.)
|
||||
// When backing up, one option is to save all non-main program files.
|
||||
// This means all folders, and files in these folders.
|
||||
Player.Message(p, "Server backup (Everything but Database) started. Please wait while backup finishes.");
|
||||
Save(true, false, p);
|
||||
} else if (type == "lite") {
|
||||
Player.Message(p, "Server backup (Everything but BlockDB tables and undo files) started. Please wait while backup finishes.");
|
||||
Save(true, true, p, true);
|
||||
} else if (type == "table") {
|
||||
if (args.Length == 2) { Player.Message(p, "You need to provide the table name to backup."); return; }
|
||||
if (!ValidName(p, args[2], "table")) return;
|
||||
@ -136,16 +139,14 @@ namespace MCGalaxy.Commands {
|
||||
return p.name.CaselessEq(Server.server_owner);
|
||||
}
|
||||
|
||||
void Save(bool withFiles, bool withDB, Player p) {
|
||||
ParameterizedThreadStart pts = new ParameterizedThreadStart(CreatePackage);
|
||||
Thread doWork = new Thread(new ParameterizedThreadStart(CreatePackage));
|
||||
doWork.Name = "MCG_SaveServer";
|
||||
List<object> param = new List<object>();
|
||||
param.Add("MCGalaxy.zip");
|
||||
param.Add(withFiles);
|
||||
param.Add(withDB);
|
||||
param.Add(p);
|
||||
doWork.Start(param);
|
||||
static void Save(bool withFiles, bool withDB, Player p, bool lite = false) {
|
||||
Thread worker = new Thread(Backup.CreatePackage);
|
||||
worker.Name = "MCG_SaveServer";
|
||||
|
||||
Backup.BackupArgs args = new Backup.BackupArgs();
|
||||
args.p = p; args.Lite = lite;
|
||||
args.Files = withFiles; args.Database = withDB;
|
||||
worker.Start(args);
|
||||
}
|
||||
|
||||
void SetToDefault() {
|
||||
@ -182,17 +183,13 @@ namespace MCGalaxy.Commands {
|
||||
Player.Message(p, "/server <public> - Make the server public. (Start listening for new connections.)");
|
||||
Player.Message(p, "/server <private> - Make the server private. (Stop listening for new connections.)");
|
||||
Player.Message(p, "/server <restore> - Restore the server from a backup.");
|
||||
Player.Message(p, "/server <backup> [all/db/allbutdb] - Make a backup. (Default is all)");
|
||||
Player.Message(p, "/server <backup> [all/db/files/lite] - Make a backup. (Default all)");
|
||||
Player.Message(p, "Backup options:");
|
||||
Player.Message(p, "all - Make a backup of the server and all SQL data. (Default)");
|
||||
Player.Message(p, "db - Just backup the database.");
|
||||
Player.Message(p, "allbutdb - Backup everything BUT the database.");
|
||||
Player.Message(p, "/server <backup> table [name] - Make a backups of that database table");
|
||||
}
|
||||
|
||||
static void CreatePackage(object par) {
|
||||
List<object> param = (List<object>)par;
|
||||
Backup.CreatePackage((string)param[0], (bool)param[1], (bool)param[2], (Player)param[3]);
|
||||
Player.Message(p, "all - Make a backup of the server and all SQL data.");
|
||||
Player.Message(p, "db - Just backup the database.");
|
||||
Player.Message(p, "files - Backup everything BUT the database.");
|
||||
Player.Message(p, "lite - Backups everything, except BlockDB and undo files.");
|
||||
Player.Message(p, "/server <backup> table [name] - Backups that database table");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -560,8 +560,8 @@
|
||||
<Compile Include="Games\CTF\Auto_CTF.cs" />
|
||||
<Compile Include="IRC\ForgeBot.cs" />
|
||||
<Compile Include="Levels\BlockQueue.cs" />
|
||||
<Compile Include="Server\Backup\Backup.cs" />
|
||||
<Compile Include="Server\Backup\BackupDB.cs" />
|
||||
<Compile Include="Server\Backup.cs" />
|
||||
<Compile Include="Server\BackupDB.cs" />
|
||||
<Compile Include="Server\Extra\Checktimer.cs" />
|
||||
<Compile Include="Server\Extra\UPnP.cs" />
|
||||
<Compile Include="Server\Colors.cs" />
|
||||
@ -702,7 +702,6 @@
|
||||
<Folder Include="Plugins" />
|
||||
<Folder Include="Plugins\Events" />
|
||||
<Folder Include="Plugins\Manager" />
|
||||
<Folder Include="Server\Backup" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
133
Server/Backup.cs
Normal file
133
Server/Backup.cs
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright 2011 MCForge
|
||||
|
||||
Dual-licensed under the Educational Community License, Version 2.0 and
|
||||
the GNU General Public License, Version 3 (the "Licenses"); you may
|
||||
not use this file except in compliance with the Licenses. You may
|
||||
obtain a copy of the Licenses at
|
||||
|
||||
http://www.opensource.org/licenses/ecl2.php
|
||||
http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the Licenses are distributed on an "AS IS"
|
||||
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Packaging;
|
||||
|
||||
namespace MCGalaxy {
|
||||
public static partial class Backup {
|
||||
|
||||
const string path = "MCGalaxy.zip";
|
||||
public class BackupArgs {
|
||||
public Player p;
|
||||
public bool Files, Database, Lite;
|
||||
}
|
||||
|
||||
public static void CreatePackage(object p) {
|
||||
BackupArgs args = (BackupArgs)p;
|
||||
if (args.Database) {
|
||||
Server.s.Log("Saving DB...");
|
||||
using (StreamWriter sql = new StreamWriter("SQL.sql"))
|
||||
BackupDatabase(sql, args.Lite);
|
||||
Server.s.Log("Saved DB to SQL.sql");
|
||||
}
|
||||
|
||||
Server.s.Log("Creating package...");
|
||||
using (ZipPackage package = (ZipPackage)ZipPackage.Open(path, FileMode.Create))
|
||||
{
|
||||
if (args.Files) {
|
||||
Server.s.Log("Collecting Directory structure...");
|
||||
string currDir = Directory.GetCurrentDirectory() + "\\";
|
||||
List<Uri> partURIs = GetAllFiles(new DirectoryInfo("./"), new Uri(currDir));
|
||||
Server.s.Log("Structure complete");
|
||||
|
||||
Server.s.Log("Saving data...");
|
||||
foreach (Uri loc in partURIs) {
|
||||
string file = Uri.UnescapeDataString(loc.ToString());
|
||||
if (args.Lite && file.Contains("extra/undo/")) continue;
|
||||
if (args.Lite && file.Contains("extra/undoPrevious")) continue;
|
||||
|
||||
if (!file.Contains(path)) {
|
||||
// Add the part to the Package
|
||||
ZipPackagePart packagePart = (ZipPackagePart)package.CreatePart(loc, "");
|
||||
|
||||
// Copy the data to the Document Part
|
||||
using (FileStream stream = new FileStream("./" + file, FileMode.Open, FileAccess.Read))
|
||||
CopyStream(stream, packagePart.GetStream());
|
||||
}
|
||||
}// end:foreach(Uri loc)
|
||||
}
|
||||
if (args.Database) { // If we don't want to back up database, we don't do this part.
|
||||
Server.s.Log("Compressing Database...");
|
||||
ZipPackagePart packagePart =
|
||||
(ZipPackagePart)package.CreatePart(new Uri("/SQL.sql", UriKind.Relative), "", CompressionOption.Normal);
|
||||
CopyStream(File.OpenRead("SQL.sql"), packagePart.GetStream());
|
||||
Server.s.Log("Database compressed.");
|
||||
}// end:if(withFiles)
|
||||
Server.s.Log("Data saved!");
|
||||
}// end:using (Package package) - Close and dispose package.
|
||||
Player.Message(args.p, "Server backup (" + (args.Files ? "Everything" + (args.Database ? "" : " but Database") : "Database") + "): Complete!");
|
||||
Server.s.Log("Server backed up!");
|
||||
}// end:CreatePackage()
|
||||
|
||||
static List<Uri> GetAllFiles(DirectoryInfo currDir, Uri baseUri) {
|
||||
List<Uri> uriList = new List<Uri>();
|
||||
foreach (FileSystemInfo entry in currDir.GetFileSystemInfos()) {
|
||||
if (entry is FileInfo) {
|
||||
// Make a relative URI
|
||||
Uri fullURI = new Uri(((FileInfo)entry).FullName);
|
||||
Uri relURI = baseUri.MakeRelativeUri(fullURI);
|
||||
if (relURI.ToString().IndexOfAny("/\\".ToCharArray()) > 0) {
|
||||
uriList.Add(PackUriHelper.CreatePartUri(relURI));
|
||||
}
|
||||
} else {
|
||||
uriList.AddRange(GetAllFiles((DirectoryInfo)entry, baseUri));
|
||||
}
|
||||
}
|
||||
return uriList;
|
||||
}
|
||||
|
||||
static void CopyStream(Stream source, Stream target) {
|
||||
const int bufSize = 0x1000;
|
||||
byte[] buf = new byte[bufSize];
|
||||
int bytesRead = 0;
|
||||
while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)
|
||||
target.Write(buf, 0, bytesRead);
|
||||
}
|
||||
|
||||
public static void ExtractPackage(object p) {
|
||||
int errors = 0;
|
||||
using (ZipPackage zip = (ZipPackage)ZipPackage.Open(File.OpenRead(path))) {
|
||||
PackagePartCollection pc = zip.GetParts();
|
||||
foreach (ZipPackagePart item in pc) {
|
||||
try {
|
||||
CopyStream(item.GetStream(), File.Create("./" + Uri.UnescapeDataString(item.Uri.ToString())));
|
||||
} catch {
|
||||
try {
|
||||
Directory.CreateDirectory("./" + item.Uri.ToString().Substring(0, item.Uri.ToString().LastIndexOfAny("\\/".ToCharArray())));
|
||||
CopyStream(item.GetStream(), File.Create("./" + Uri.UnescapeDataString(item.Uri.ToString())));
|
||||
} catch (IOException e) {
|
||||
Server.ErrorLog(e);
|
||||
Server.s.Log("Caught ignoreable Error. See log for more details. Will continue with rest of files.");
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
// To make life easier, we reload settings now, to maker it less likely to need restart
|
||||
Command.all.Find("server").Use(null, "reload"); //Reload, as console
|
||||
if (item.Uri.ToString().ToLower().Contains("sql.sql"))
|
||||
{ // If it's in there, they backed it up, meaning they want it restored
|
||||
Backup.fillDatabase(item.GetStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
Player.Message((Player)p, "Server restored" + (errors > 0 ? " with errors. May be a partial restore" : "") + ". Restart is reccommended, though not required.");
|
||||
}
|
||||
}
|
||||
}
|
268
Server/BackupDB.cs
Normal file
268
Server/BackupDB.cs
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright 2011 MCForge
|
||||
|
||||
Dual-licensed under the Educational Community License, Version 2.0 and
|
||||
the GNU General Public License, Version 3 (the "Licenses"); you may
|
||||
not use this file except in compliance with the Licenses. You may
|
||||
obtain a copy of the Licenses at
|
||||
|
||||
http://www.opensource.org/licenses/ecl2.php
|
||||
http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the Licenses are distributed on an "AS IS"
|
||||
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MCGalaxy.SQL;
|
||||
|
||||
namespace MCGalaxy {
|
||||
public static partial class Backup {
|
||||
|
||||
public static void BackupDatabase(StreamWriter sql, bool lite) {
|
||||
//We technically know all tables in the DB... But since this is MySQL, we can also get them all with a MySQL command
|
||||
//So we show the tables, and store the result.
|
||||
//Also output information data (Same format as phpMyAdmin's dump)
|
||||
|
||||
//Important note: This does NOT account for foreign keys, BLOB's etc. It only works for what we actually put in the db.
|
||||
|
||||
sql.WriteLine("-- MCGalaxy SQL Database Dump");
|
||||
sql.WriteLine("-- version 1.5");
|
||||
sql.WriteLine("-- http://mcgalaxy.ml");
|
||||
sql.WriteLine("--");
|
||||
sql.WriteLine("-- Host: {0}", Server.MySQLHost);
|
||||
sql.WriteLine("-- Generation Time: {0} at {1}", DateTime.Now.Date, DateTime.Now.TimeOfDay);
|
||||
sql.WriteLine("-- MCGalaxy Version: {0}", Server.Version);
|
||||
sql.WriteLine();
|
||||
sql.WriteLine();
|
||||
|
||||
List<string> sqlTables = GetTables();
|
||||
foreach (string name in sqlTables) {
|
||||
if (lite && name.CaselessStarts("Block")) continue;
|
||||
BackupTable(name, sql);
|
||||
}
|
||||
}
|
||||
|
||||
public static void BackupTable(string tableName, StreamWriter sql) {
|
||||
//For each table, we iterate through all rows, (and save them)
|
||||
sql.WriteLine("-- --------------------------------------------------------");
|
||||
sql.WriteLine();
|
||||
sql.WriteLine("--");
|
||||
sql.WriteLine("-- Table structure for table `{0}`", tableName);
|
||||
sql.WriteLine("--");
|
||||
sql.WriteLine();
|
||||
List<string[]> tableSchema = WriteTableSchema(tableName, sql);
|
||||
|
||||
using (DataTable data = Database.fillData("SELECT * FROM `" + tableName + "`")) {
|
||||
if (data.Rows.Count == 0) {
|
||||
sql.WriteLine("-- No data in table `{0}`!", tableName);
|
||||
sql.WriteLine();
|
||||
return;
|
||||
}
|
||||
|
||||
sql.WriteLine("--");
|
||||
sql.WriteLine("-- Dumping data for table `{0}`", tableName);
|
||||
sql.WriteLine("--");
|
||||
sql.WriteLine();
|
||||
List<DataColumn> allCols = new List<DataColumn>();
|
||||
foreach (DataColumn col in data.Columns)
|
||||
allCols.Add(col);
|
||||
|
||||
foreach (DataRow row in data.Rows) { //We rely on the correct datatype being given here.
|
||||
sql.WriteLine();
|
||||
sql.Write("INSERT INTO `{0}` (`", tableName);
|
||||
foreach (string[] rParams in tableSchema) {
|
||||
sql.Write(rParams[0]);
|
||||
sql.Write((tableSchema[tableSchema.Count - 1].Equals(rParams) ? "`) VALUES" : "`, `"));
|
||||
}
|
||||
|
||||
sql.WriteLine();
|
||||
sql.Write("(");
|
||||
for (int col = 0; col < row.ItemArray.Length; col++) {
|
||||
//The values themselves can be integers or strings, or null
|
||||
Type eleType = allCols[col].DataType;
|
||||
if (row.IsNull(col)) {
|
||||
sql.Write("NULL");
|
||||
} else if (eleType.Name.Equals("DateTime")) { // special format
|
||||
DateTime dt = row.Field<DateTime>(col);
|
||||
sql.Write("'{0:yyyy-MM-dd HH:mm:ss.ffff}'", dt);
|
||||
} else if (eleType.Name.Equals("Boolean")) {
|
||||
sql.Write(row.Field<Boolean>(col) ? "1" : "0");
|
||||
} else if (eleType.Name.Equals("String")) { // Requires ''
|
||||
sql.Write("'{0}'", row.Field<string>(col));
|
||||
} else {
|
||||
sql.Write(row.Field<Object>(col)); // We assume all other data is left as-is
|
||||
//This includes numbers, blobs, etc. (As well as objects, but we don't save them into the database)
|
||||
}
|
||||
sql.Write((col < row.ItemArray.Length - 1 ? ", " : ");"));
|
||||
}
|
||||
}
|
||||
sql.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
static List<string[]> WriteTableSchema(string tableName, StreamWriter sql) {
|
||||
List<string[]> tableSchema = new List<string[]>();
|
||||
if (Server.useMySQL) {
|
||||
string[] rowParams;
|
||||
string pri;
|
||||
sql.WriteLine("CREATE TABLE IF NOT EXISTS `{0}` (", tableName);
|
||||
using (DataTable schema = Database.fillData("DESCRIBE " + tableName)) {
|
||||
rowParams = new string[schema.Columns.Count];
|
||||
pri = "";
|
||||
foreach (DataRow row in schema.Rows) {
|
||||
//Save the info contained to file
|
||||
List<string> tmp = new List<string>();
|
||||
for (int col = 0; col < schema.Columns.Count; col++)
|
||||
tmp.Add(row.Field<string>(col));
|
||||
|
||||
rowParams = tmp.ToArray();
|
||||
rowParams[2] = (rowParams[2].ToLower().Equals("no") ? "NOT " : "DEFAULT ") + "NULL";
|
||||
pri += (rowParams[3].ToLower().Equals("pri") ? rowParams[0] + ";" : "");
|
||||
sql.WriteLine("`{0}` {1} {2}" + (rowParams[5].Equals("") ? "" : " {5}") + (pri.Equals("") && row == schema.Rows[schema.Rows.Count - 1] ? "" : ","), rowParams);
|
||||
tableSchema.Add(rowParams);
|
||||
}
|
||||
}
|
||||
|
||||
if (pri != "") {
|
||||
string[] tmp = pri.Substring(0, pri.Length - 1).Split(';');
|
||||
sql.Write("PRIMARY KEY (`");
|
||||
foreach (string prim in tmp) {
|
||||
sql.Write(prim);
|
||||
sql.Write("`" + (tmp[tmp.Length - 1].Equals(prim) ? ")" : ", `"));
|
||||
}
|
||||
}
|
||||
sql.WriteLine(");");
|
||||
} else {
|
||||
using (DataTable tableSQL = Database.fillData("SELECT sql FROM" +
|
||||
" (SELECT * FROM sqlite_master UNION ALL" +
|
||||
" SELECT * FROM sqlite_temp_master)" +
|
||||
"WHERE tbl_name LIKE '" + tableName + "'" +
|
||||
" AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'" +
|
||||
"ORDER BY substr(type,2,1), name"))
|
||||
{
|
||||
//just print out the data in the table.
|
||||
foreach (DataRow row in tableSQL.Rows) {
|
||||
string tableSQLString = row.Field<string>(0);
|
||||
sql.WriteLine(tableSQLString.Replace(" " + tableName, " `" + tableName + "`").Replace("CREATE TABLE `" + tableName + "`", "CREATE TABLE IF NOT EXISTS `" + tableName + "`") + ";");
|
||||
//We parse this ourselves to find the actual types.
|
||||
tableSchema = getSchema(tableSQLString);
|
||||
}
|
||||
}
|
||||
}
|
||||
sql.WriteLine();
|
||||
return tableSchema;
|
||||
}
|
||||
|
||||
static List<string[]> getSchema(string tableSQLString) {
|
||||
// All SQL for creating tables looks like "CREATE TABLE [IF NOT EXISTS] <TableName> (<ColumnDef>[, ... [, PRIMARY KEY (<ColumnName>[, ...])]])
|
||||
// <ColumnDef> = <name> <type> [[NOT|DEFAULT] NULL] [PRIMARY KEY] [AUTO_INCREMENT]
|
||||
List<string[]> schema = new List<string[]>();
|
||||
int foundStart = tableSQLString.IndexOf("(") + 1;
|
||||
int foundLength = tableSQLString.LastIndexOf(")") - foundStart;
|
||||
tableSQLString = tableSQLString.Substring(foundStart, foundLength);
|
||||
// Now we have everything inside the parenthisies.
|
||||
string[] column = tableSQLString.Split(',');
|
||||
foreach (string col in column)
|
||||
{
|
||||
if (!col.ToUpper().StartsWith("PRIMARY KEY"))
|
||||
{
|
||||
string[] split = col.TrimStart('\n', '\r', '\t').Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
//Just to make it the same as the MySQL schema.
|
||||
schema.Add(new string[] { split[0].Trim('`'), split[1].Trim('\t', '`'),
|
||||
( split.Count() > 2 ? (split[2].Trim('\t', '`').ToUpper() == "NOT" ? "NOT NULL" : "DEFAULT NULL") : ""),
|
||||
( split.Count() > 2 ? (split[split.Count() - 2].Trim('\t', '`').ToUpper() == "PRIMARY" && split[split.Count() - 1].Trim('\t', '`').ToUpper() == "KEY" ? "PRI" : "") : ""),
|
||||
"NULL",
|
||||
(split.Contains("AUTO_INCREMENT") || split.Contains("AUTOINCREMENT") ? "AUTO_INCREMENT" : "")});
|
||||
}
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
static List<string> GetTables() {
|
||||
List<string> tableNames = new List<string>();
|
||||
string syntax = Server.useMySQL ? "SHOW TABLES" : "SELECT * FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'";
|
||||
using (DataTable tables = Database.fillData(syntax)) {
|
||||
foreach (DataRow row in tables.Rows) {
|
||||
string tableName = row.Field<string>((Server.useMySQL ? 0 : 1));
|
||||
tableNames.Add(tableName);
|
||||
}
|
||||
}
|
||||
return tableNames;
|
||||
}
|
||||
|
||||
internal static void fillDatabase(Stream stream) {
|
||||
//Backup
|
||||
using (FileStream backup = File.Create("backup.sql"))
|
||||
BackupDatabase(new StreamWriter(backup), false);
|
||||
|
||||
//Delete old
|
||||
List<string> tables = GetTables();
|
||||
foreach (string name in tables)
|
||||
Database.executeQuery(String.Format("DROP TABLE `{0}`", name));
|
||||
|
||||
//Make new
|
||||
string script = new StreamReader(stream).ReadToEnd();
|
||||
string[] cmds = script.Split(';');
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
using (BulkTransaction helper = BulkTransaction.Create()) {
|
||||
foreach (string cmd in cmds) {
|
||||
string newCmd = cmd.Trim(" \r\n\t".ToCharArray());
|
||||
int index = newCmd.ToUpper().IndexOf("CREATE TABLE");
|
||||
if (index > -1) {
|
||||
newCmd = newCmd.Remove(0, index);
|
||||
//Do we have a primary key?
|
||||
try
|
||||
{
|
||||
if (Server.useMySQL)
|
||||
{
|
||||
int priIndex = newCmd.ToUpper().IndexOf(" PRIMARY KEY AUTOINCREMENT");
|
||||
int priCount = " PRIMARY KEY AUTOINCREMENT".Length;
|
||||
int attIdx = newCmd.Substring(0, newCmd.Substring(0, priIndex - 1).LastIndexOfAny("` \n".ToCharArray())).LastIndexOfAny("` \n".ToCharArray()) + 1;
|
||||
int attIdxEnd = newCmd.IndexOfAny("` \n".ToCharArray(), attIdx) - 1;
|
||||
string attName = newCmd.Substring(attIdx, attIdxEnd - attIdx + 1).Trim(' ', '\n', '`', '\r');
|
||||
//For speed, we just delete this, and add it to the attribute name, then delete the auto_increment clause.
|
||||
newCmd = newCmd.Remove(priIndex, priCount);
|
||||
newCmd = newCmd.Insert(newCmd.LastIndexOf(")"), ", PRIMARY KEY (`" + attName + "`)");
|
||||
newCmd = newCmd.Insert(newCmd.IndexOf(',', priIndex), " AUTO_INCREMENT");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int priIndex = newCmd.ToUpper().IndexOf(",\r\nPRIMARY KEY");
|
||||
int priIndexEnd = newCmd.ToUpper().IndexOf(')', priIndex);
|
||||
int attIdx = newCmd.IndexOf("(", priIndex) + 1;
|
||||
int attIdxEnd = priIndexEnd - 1;
|
||||
string attName = newCmd.Substring(attIdx, attIdxEnd - attIdx + 1);
|
||||
newCmd = newCmd.Remove(priIndex, priIndexEnd - priIndex + 1);
|
||||
int start = newCmd.IndexOf(attName) + attName.Length;
|
||||
int end = newCmd.IndexOf(',');
|
||||
newCmd = newCmd.Remove(start, end - start);
|
||||
newCmd = newCmd.Insert(newCmd.IndexOf(attName) + attName.Length, " INTEGER PRIMARY KEY AUTOINCREMENT");
|
||||
newCmd = newCmd.Replace(" auto_increment", "").Replace(" AUTO_INCREMENT", "").Replace("True", "1").Replace("False", "0");
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException) { } // If we don't, just ignore it.
|
||||
}
|
||||
//Run the command in the transaction.
|
||||
helper.Execute(newCmd.Replace(" unsigned", "").Replace(" UNSIGNED", "") + ";");
|
||||
// sb.Append(newCmd).Append(";\n");
|
||||
}
|
||||
helper.Commit();
|
||||
}
|
||||
//Not sure if order matters.
|
||||
//AUTO_INCREMENT is changed to AUTOINCREMENT for MySQL -> SQLite
|
||||
//AUTOINCREMENT is changed to AUTO_INCREMENT for SQLite -> MySQL
|
||||
// All we should have in the script file is CREATE TABLE and INSERT INTO commands.
|
||||
//executeQuery(sb.ToString().Replace(" unsigned", "").Replace(" UNSIGNED", ""));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user