Postgres 中的 DBCreate
一篇关于使用 PostgreSQL 创建数据库的文章。

引言
在安装数据库应用程序时,许多客户希望看到针对数据库执行的 SQL 代码。 他们中的大部分需要查看此代码以确保安全,有时还需要符合萨班斯-奥克斯利法规。 我想知道是否可以达到一个状态,即同时拥有 .SQL 文件以及一个用于在数据库上执行代码的程序。 过去,我们只是启动一个 shell,并向系统管理员显示结果。 我们还会检查输出文件中的“error”(错误)等词语。 虽然这可行,但这不是最优雅的方法。
Using the Code
该程序有一个主屏幕和两个面板,面板的启用与输入有关。 第一个面板收集执行一系列 SQL 所需的信息。 按钮用于 后退 和 下一步 序列,但按钮名称也会在最后一步更改为 开始。 第二个屏幕显示一个文本框,该文本框将在从输入文件读取每个 SQL 语句后进行更新。 诀窍是将您想要的所有控件放入其各自的面板中。 这样,当您启用并显示所需的面板时,只需对面板进行操作,而无需对面板内的每个控件进行操作。
///
/// initialize the variables and screens.
///
public DBIns()
{
InitializeComponent();
panel2.Enabled = false;
panel2.Visible = false;
btnBack.Enabled = false;
}
当按下按钮时,代码必须检查其当前状态,并更改需要更改的任何按钮名称,同时使面板可见并启用。 由于我实际上计划使用这段代码,因此我还添加了 errorprovider
来检查有效输入,然后再进入第二个面板。
///
/// click the back button. determine what to do.
///
private void btnBack_Click(object sender, EventArgs e)
{
if (panel1.Enabled != true)
{
panel2.Enabled = false;
panel2.Visible = false;
panel1.Enabled = true;
panel1.Visible = true;
btnNext.Text = "Next ->"; // change the button to read next.
btnBack.Enabled = false;
}
}
///
/// click the next button. determine what to do.
///
private void btnNext_Click(object sender, EventArgs e)
{
errorProvider1.Clear();
// if panel 1 is enabled and a next button was pressed we
// want to display panel2 and allow the user to press the start button.
if (panel1.Enabled == true)
{
// Check to see if the data was entered before we proceeed.
if (txtServer.Text.Length == 0)
{
errorProvider1.SetError(txtServer,
"Please enter a valid server name");
return;
}
// Check to see if the data was entered before we proceeed.
if (txtDBName.Text.Length == 0)
{
errorProvider1.SetError(txtDBName,
"Please enter a valid database name");
return;
}
// Check to see if the data was entered before we proceeed.
if (txtUser.Text.Length == 0)
{
errorProvider1.SetError(txtUser, "Please enter a valid User name");
return;
}
// Check to see if the data was entered before we proceeed.
if (txtPassword.Text.Length == 0)
{
errorProvider1.SetError(txtPassword,
"Please enter a valid password");
return;
}
panel1.Enabled = false;
panel1.Visible = false;
panel2.Enabled = true;
panel2.Visible = true;
btnNext.Text = "Start";
btnBack.Enabled = true;
panel2.Visible = true;
textBox1.TabIndex = 1;
textBox1.Focus();
btnBack.TabIndex = 2;
btnNext.TabIndex = 3;
}
else
{
NpgsqlRtns cl1;
bool bCreateDB;
string strDBName;
string strServer;
string strUser;
string strPassword;
btnBack.Enabled = false;
btnNext.Enabled = false;
cl1 = new NpgsqlRtns();
bCreateDB = chkBoxCreateDB.Checked;
strDBName = txtDBName.Text;
strServer = txtServer.Text;
strUser = txtUser.Text;
strPassword = txtPassword.Text;
Subscribe(cl1);
cl1.StartConv(bCreateDB, strDBName, strServer, strUser, strPassword);
}
}
startconv
过程处理数据库的创建(如果选中)以及解析文件中的 SQL 命令。
public int StartConv(bool bCreateDB, string strDBName, string strServer,
string strUser, string strPassword)
{
int ians = 0;
ians = doConv(bCreateDB, strDBName, strServer, strUser, strPassword);
return (ians);
}
///
/// This routine does the actual database conversion process.
///
private int doConv(bool bCreateDB, string strDBName, string strServer,
string strUser, string strPassword)
{
int ians = 0;
string strlastCommand;
string strCommand;
FileRtns frtn;
NpgsqlConnection conn;
//
// first use the SA account to create a datbase if requested.
//
strCommand = string.Format(
"Server={0};Port=5432;User Id={1};Password={2};Database=postgres;",
strServer, strUser, strPassword);
conn = new NpgsqlConnection(strCommand);
conn.Open();
// if we were requested toc reate the datbase then do so
if (bCreateDB)
{
strCommand = string.Format(
"CREATE DATABASE \"{0}\" WITH OWNER = postgres ENCODING = 'WIN1252';",
strDBName);
strlastCommand = strCommand;
NpgsqlCommand command = new NpgsqlCommand(strCommand, conn);
try
{
command.ExecuteScalar();
strResult = "Create Database - Successful";
}
catch
{
strResult = "Error ";
}
if (Tick != null)
{
Tick(this, e);
}
}
conn.Close();
//
// Now log into the requested database and issue the sql statements.
//
// create a file routines class to read the sql statements form the file.
frtn = new FileRtns();
frtn.FileOpen();
strCommand = string.Format(
"Server={1};Port=5432;User Id={2};Password={3};Database={0};",
strDBName, strServer, strUser, strPassword);
conn = new NpgsqlConnection(strCommand);
conn.Open();
// while there are statements in the file read them.
while (true)
{
strCommand = frtn.FileRead();
if (strCommand.Length == 0)
{
break; // we are at the end of the file.
}
strlastCommand = strCommand;
NpgsqlCommand command = new NpgsqlCommand(strCommand, conn);
// execute the sql statement.
try
{
command.ExecuteScalar();
strResult = findCommand(strCommand) + " - Successful";
}
catch
{
strResult = findCommand(strCommand) + " - Error";
}
if (Tick != null)
{
Tick(this, e);
}
}
conn.Close();
frtn.FileClose();
strResult = "Finished";
if (Tick != null)
{
Tick(this, e);
}
return (ians);
}
在本版本中,文件解析器会读取直到第一个分号。 我知道这仅适用于单行命令(这有很多),但对于函数而言会失败。 在下一个版本中,我将更新此功能以包含函数。 为了使这项工作更容易,我已经封装了该类。
///
/// Read the frist line from the file.
/// We will read until the first semicolon since that ends the sql statement.
///
public string FileRead()
{
string strResult = "";
string strBuffer = "";
while ((sr.EndOfStream)!= true) {
strBuffer = sr.ReadLine();
strBuffer = strBuffer.Trim();
if (strBuffer.EndsWith(";"))
{
strResult += strBuffer;
break;
}
strResult += strBuffer;
}
return (strResult);
}
执行命令后,会对其进行解析以进行显示,并发送一个事件。 主程序捕获该事件,然后在文本框中向用户显示该命令。
虽然有其他程序专注于数据库创建,但由于 SQL 文件可以独立使用,也可以作为此程序的一部分使用,因此该程序具有一定的独特性。 如果您想下载 PostgreSQL,请访问 此处。
其他注意事项
下一个版本将包括对函数的修复,以及对 PostgreSQL 的其他一些改进。
历史
12 月 19 日 - 第一个版本