How can I dump some of the tables from my mysql database into an sql file in C#?
Is there a class which does this?
UPDATE: just wanted to mention to DO NOT USE mysqldump, because this application will be installed on many computers and the mysql folder could be on different places.
Dotconnect for mysql might have this feature, but I don't know about the free version.
Otherwise you could just invoke the mysqldump utility and do something like this:
public void DumpMySQLDb(string user, string password, string database, string outputFile) {
var commandLine = string.Format("mysqldump --user={1}--password={2} --hex-blob --databases {3}",
user, password, database)
var process = new Process();
process.StartInfo = new ProcessStartInfo {
FileName = "cmd",
Arguments = string.Format( "/c \"{0}\" > {1}", commandLine, outputFile )
};
process.Start();
}
I built up the sql string table by talbe in the end.
Related
We've deployed nodes and posted a transaction from one node to another using corda and the same got stored in h2 database in "NODE_TRANSACTIONS" table.
TRANSACTION_VALUE column in NODE_TRANSACTIONS table is of BLOB data type.
Please suggest how to extract data from this column in a readable format
We've tried extracting data using resultset.getBinaryStream in java, but not sure of the supported file type in which it needs to be read. Tried with file types image/txt/pdf etc but none of the files were in readable format.
static String url = "jdbc:h2:tcp://localhost:12345/node";
static String username = "sa";
static String password = "";
Class.forName("oracle.h2.Driver");
Connection conn = DriverManager.getConnection(url, username, password);
System.out.println("getting connection: " + conn);
String sql = "SELECT TX_ID, TRANSACTION_VALUE FROM NODE_TRANSACTIONS where rownum<2";
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
InputStream data=rs.getBinaryStream(2);
File file = new File("D:\\blob.txt");
FileOutputStream fos = new FileOutputStream(file);
byte[] buffer = new byte[1];
while (data.read(buffer) > 0) {
fos.write(buffer);
}
fos.close();
}
conn.close();
Also, please suggest any other way to read the column data using h2 database functions (or) oracle functions
I expect the output to be in a readable format
If you're after having state data stored in a readable format in the database following a transaction, the state must implement the QueryableState interface.
See the docs at https://docs.corda.net/api-persistence.html and the example at https://github.com/corda/cordapp-example/blob/release-V4/java-source/src/main/java/com/example/state/IOUState.java
If I restore from Sql Server no problem, but if I do it through my application, the database is stuck in "restoring state".
I found some advice saying to put noRecovery = false, but this didn't change anything.
If I remove the "with move" option, it works: after the restore the DB is in a normal state.
The thing that I would like to understand is: does "with move" modify a sql server table?
Because if I launch the restore the first time without "with move" it says that he could not find the specified path. Otherwise, if I launch the restore with this option, and then one second time without it, it works. So there must be some tables that sql server uses to map the logical name with a physical path, how can I modify this table?
Here is the code:
SqlConnection sqlConnection = new SqlConnection(string.Format("Data Source={0};Initial Catalog={1};Integrated Security=True", database.SqlServerId, database.Name));
ServerConnection connection = new ServerConnection(sqlConnection);
Server sqlServer = new Server(connection);
Restore rstDatabase = new Restore();
rstDatabase.Action = RestoreActionType.Database;
rstDatabase.Database = backupFile.Name;
BackupDeviceItem bkpDevice = new BackupDeviceItem(backupFile.FileName, DeviceType.File);
rstDatabase.Devices.Add(bkpDevice);
rstDatabase.ReplaceDatabase = true;
rstDatabase.NoRecovery = false;
string dbLogicalName = "";
string logLogicalName = "";
sqlConnection.Open();
SqlCommand command = new SqlCommand(string.Format("RESTORE FILELISTONLY FROM DISK = '{0}'", backupFile.FileName), sqlConnection);
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
if (reader.GetString(2) == "D")
dbLogicalName = reader.GetString(0);
if (reader.GetString(2) == "L")
logLogicalName = reader.GetString(0);
}
}
reader.Close();
rstDatabase.RelocateFiles.Add(new RelocateFile(dbLogicalName, backupFile.DatabaseFile));
rstDatabase.RelocateFiles.Add(new RelocateFile(logLogicalName, backupFile.LogsFile));
//Restore
rstDatabase.SqlRestore(sqlServer);
rstDatabase.Devices.Remove(bkpDevice);
sqlConnection.Close();
connection.Disconnect();
The thing that I would like to understand is: does "with move" modify a sql server table?
Not necessarily, unless you modify the default databases path in the instance, which you could do in SSMS following these steps:
https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/view-or-change-the-default-locations-for-data-and-log-files
But as someone said, try to fix that on your own application. Do not attempt to modify this on the system database. It could bring unexpected results if you do that.
I think you know that, but WITH MOVE tells the SQL Server to reallocate the restored database in different path than the default path.
I tried a few solutions and below is the most straight forward one but I get the error below
Logical file 'RestoredProcessMananger' is not part of database 'RestoredProcessMananger'. Use RESTORE FILELISTONLY to list the logical file names.
RESTORE DATABASE is terminating abnormally.
What am I doing wrong ? The idea is to create DLL to be used by other programs the allow a baseline database to be reloaded on a server overwriting whatever is there..
ServerConnection connection = new ServerConnection("xxx", "sa", "srv$xxx");
Server svr =new Server(connection);
Restore res = new Restore();
res.Database = "RestoredProcessMananger";
res.Action = RestoreActionType.Database;
res.Devices.AddDevice(#"C:\temp\ProcessManager.bak", DeviceType.File);
res.ReplaceDatabase = true;
res.RelocateFiles.Add(new RelocateFile("RestoredProcessMananger", _
#"c:\ProcessManager2.mdf"));
res.RelocateFiles.Add(new RelocateFile("RestoredProcessMananger_Log", _
#"c:\ProcessManager2_log.ldf"));
res.SqlRestore(svr);
svr.Refresh();
EDIT 1: fixed
public static void RestoreDatabase(string Server, //sqlserver //from CONFIG
string BackupFilePath, //where the bak file I want to restore //from CONFIG
string destinationDatabaseName, //what the restored database will be called //from CONFIG
string DatabaseFolder, //where the data/log files for the destination (break into 2 variables (2 different locations)) (get from GetDatabaseMDFFilePathName)
string DatabaseFileName, //the destination MDF file name (get from GetDatabaseMDFFilePathName)
string DatabaseLogFileName) //the destination LDF file name (get from GetDatabaseMDFFilePathName)
{
Server myServer = GetDatabases("xxx");
Restore myRestore = new Restore();
myRestore.Database = destinationDatabaseName;
Database currentDb = myServer.Databases[destinationDatabaseName];
if (currentDb != null)
myServer.KillAllProcesses(destinationDatabaseName);
myRestore.Devices.AddDevice(BackupFilePath, DeviceType.File);
string DataFileLocation = DatabaseFolder + "\\" + destinationDatabaseName + ".mdf";
string LogFileLocation = DatabaseFolder + "\\" + destinationDatabaseName + "_log.ldf";
myRestore.RelocateFiles.Add(new RelocateFile(DatabaseFileName, DataFileLocation));
myRestore.RelocateFiles.Add(new RelocateFile(DatabaseLogFileName, LogFileLocation));
myRestore.ReplaceDatabase = true;
myRestore.PercentCompleteNotification = 10;
myRestore.SqlRestore(myServer);
currentDb = myServer.Databases[destinationDatabaseName];
currentDb.SetOnline();
}
The error indicates that RestoredProcessMananger is not the name of a logical file contained in your backup file.
Have you used RESTORE FILELISTONLY ... to list the files contained in the .BAK file?
For instance, if your backup file is named C:\MyBackupFile.bak you would need to run the following query from SQL Server Management Studio (or SQLCMD, etc):
RESTORE FILELISTONLY FROM DISK='C:\MyBackupFile.bak';
This will provide a list of the logical files contained in the backup file. You will then need to pass the name of one of these files into your RelocateFile code.
I would like to retreive some binary data from a varbinary(max) column in a SQL Server database for debugging purposes.
What is the easiest way to get this data into a local binary file, preferably without having to write a throw-away console application?
I have tried using SQL Server Management Studio (with the "results to file" option) but this outputs a hex encoded binary string to the file, rather than the raw binary data.
I can't think of any easier way to do this than a throw away bit of C#...
static void Main(string[] args)
{
GetBinaryDataToFile("Server=localhost;Initial Catalog=ReportServer;Integrated Security=true", "D:\\temp.dat");
}
public static void GetBinaryDataToFile(string connectionString, string path)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT Sid FROM Users WHERE UserID = '62066184-8403-494E-A571-438ABF938A4F'";
command.CommandType = CommandType.Text;
using (SqlDataReader dataReader = command.ExecuteReader())
{
if (dataReader.Read())
{
SqlBinary sqlBinary = dataReader.GetSqlBinary(0);
File.WriteAllBytes(path, sqlBinary.Value);
}
dataReader.Close();
}
}
connection.Close();
}
}
This code has been tested using the Users.Sid column (which is of varbinary type) in a default installation of SQL Server wih Reporting Services.
I loved the LinqPad suggestion. I tried it and had a query that spit out the binary to a file within 10 minutes. No VS Project, no build - and now the script is saved and I can pull it up anytime. So cool!
LinqPad script:
var g = from pd in Archives
where pd.ArchiveId == 123
select pd;
var q = from p in printDocs
where p.DocumentId == g.SingleOrDefault().DocumentId
select p;
File.WriteAllBytes("C:\\temp.pdf", q.SingleOrDefault().Pdf.ToArray());
I've found this solution with bcp command (run from command prompt):
c:\temp>bcp "select MYVARBINARYCOL from MYTABLE where id = 1234" queryout "c:\filename.pdf" -S MYSQLSERVER\MYINSTANCE -T
Enter the file storage type of field filedata [varbinary(max)]:
Enter prefix-length of field filedata [8]: 0
Enter length of field filedata [0]:
Enter field terminator [none]:
Do you want to save this format information in a file? [Y/n] n
Starting copy...
1 rows copied.
Network packet size (bytes): 4096
Clock Time (ms.) Total : 15 Average : (66.67 rows per sec.)
I used the -T option to use windows authentication to connect to the DB. If you use password auth, you'll need to use the -U and -P switches to specify a username and password.
But I also like LinqPad suggestion in Robb Sadler's answer and somehow prefer it.
I am trying to return the physical file path of a database's mdf/ldf files.
I have tried using the following code:
Server srv = new Server(connection);
Database database = new Database(srv, dbName);
string filePath = database.PrimaryFilePath;
However this throws an exception "'database.PrimaryFilePath' threw an exception of type 'Microsoft.SqlServer.Management.Smo.PropertyNotSetException' - even though the database I'm running this against exists, and its mdf file is located in c:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL
What am I doing wrong?
Usually the problem is with the DefaultFile property being null. The default data file is where the data files are stored on the instance of SQL Server unless otherwise specified in the FileName property. If no other default location has been specified the property will return an empty string.
So, this property brings back nothing (empty string) if you didn't set the default location.
A workaround is to check the DefaultFile property, if it returns an empty string use SMO to get the master database then use the Database.PrimaryFilePath property to retrieve the Default Data File Location (since it hasn't changed)
Since you say the problem is with your PrimaryFilePath:
Confirm that your connection is open
Confirm that other properties are available
This is how I do it, prepared for multiple file names. Access database.LogFiles to get the same list of log file names:
private static IList<string> _GetAttachedFileNames(Database database)
{
var fileNames = new List<string>();
foreach (FileGroup group in database.FileGroups)
foreach (DataFile file in group.Files)
fileNames.Add(file.FileName);
return fileNames;
}
Server srv = new Server(connection);
DatabaseCollection dbc = svr.Databases;
Database database = dbc["dbName"];
string filePath = database.PrimaryFilePath;
I think the easiest approach would be to run sql script on your sql server instance which will always return you correct data and log file paths. The following sql will do the trick
SELECT
db.name AS DBName,
(select mf.Physical_Name FROM sys.master_files mf where mf.type_desc = 'ROWS' and db.database_id = mf.database_id ) as DataFile,
(select mf.Physical_Name FROM sys.master_files mf where mf.type_desc = 'LOG' and db.database_id = mf.database_id ) as LogFile
FROM sys.databases db
order by DBName
You can still execute this sql using SMO if you want to, which will return you a dataset and then you can extract that information.
var result = new List();
var server = new Server( serverInstanceName );
var data = server.Databases[ "master" ].ExecuteWithResults(sql);
foreach ( DataRow row in data.Tables[ 0 ].Rows )
result.Add( new DatabaseInfo( row[ "DBName" ].ToString(), row[ "DataFile" ].ToString(), row[ "LogFile" ].ToString() ) );
return result;
If you will use this snippet then make sure to create a DatabaseInfo class which will store the information returned from Sql server instance.
using Smo = Microsoft.SqlServer.Management.Smo;
public string GetDataBasePath(string strDatabaseName)
{
ServerConnection srvConn = new ServerConnection();
srvConn.ConnectionString = "<your connection string goes here>";
Server srv = new Server(srvConn);
foreach (Smo.Database db in srv.Databases)
{
if (string.Compare(strDatabaseName, db.Name, true) == 0)
{
return db.PrimaryFilePath;
}
}
return string.Empty;
}