Introduction
In my last project, I needed to develop a class that simplifies the execution of multiples queries against my MySQL database. I developed the class for ease of use and "do more for less". What I want to show here is how to:
- Create the
OdbcExecuter
class.
Using the Code
The class I implemented is based on one Windows form which also allows feedback to users about the transaction. To use it, you only have to add the class to your project. Start by adding a Windows form and declaring some private variables:
Private variables:
public class OdbcExecuter : System.Windows.Forms.Form
{
private string[] QueryCollection = new string[1];
private string connstring;
private string waitmessage = "EXECUTING THE QUERIES";
private int nCommands = 0;
Next, the properties to set the above variables:
public string ConnectionString
{
get
{
return(connstring);
}
set
{
this.connstring = value;
}
}
public string WaitMessage
{
get
{
return(waitmessage);
}
set
{
WaitMessage.Text = value;
}
}
OK, at this phase, we coded the two properties to treat the internal variables for use in our future methods. As the string array of queries grows, we must resize it. Let's start by adding the private function to deal with the array growth:
private Array ResizeArray(Array QueryArray, int NewSize)
{
Type QueryArrayType = QueryArray.GetType().GetElementType();
Array NewQueryArray = Array.CreateInstance(QueryArrayType, NewSize);
Array.Copy(QueryArray, 0, NewQueryArray, 0,
Math.Min(QueryArray.Length, NewSize));
return NewQueryArray;
}
So, how this function works. First, we get the type of elements on the array, declare a new object of type Type
and build a new array from the original array. Next, copy our existing data from the original array to our new fresh array and finally, return it. With this function, we can add as much queries as we need, that this function will just resize our array as needed.
Next, we will code our LockTables
and ReleaseTables
functions, but first, a little explanation about the MySQL functions we will use.
Since the release of MySQL version 3.21.27, the database engine permits user level locks. If you have MySQL installed on your system, you can try out the GET_LOCK
and RELEASE_LOCK
functions. Lately, MySQL developers added the IS_FREE_LOCK
function to check the status of the locks. This function is only available from the version 4.0.2.
Now, back to code. The LockTable
is the function dealing with lock and feedback to user, it will continually cycle until it gets the lock. I didn't add a timeout control variable because I didn't need it. Finally, the ReleaseTable
function will deal with the release of database user level lock. I coded the LockTable
and ReleaseTable
functions with try
/ catch
block to deal safely with database exceptions. The functions will return true if everything goes well or false if an exception occurred.
Finally, the core public functions: AddQuery
and ExecuteQueries
. The function AddQuery
simply adds queries to our QueryCollection
string array. It uses the ResizeArray
function described above to grow the string array QueryCollection
as needed. ExecuteQueries
, is our main function that will perform all the action. It makes a call to LockTable
function to lock the tables at user level, initiates a Transaction
object, places the queries against the database, commits or rollbacks the transaction and finally calls the ReleaseTable
function and returns the result from the execution operation which can be true for things run well, or false on exception.
private bool LockTables()
{
OdbcConnection OdbcMyConnection = new OdbcConnection(connstring);
OdbcMyConnection.Open();
bool bStatus = false;
OdbcCommand OdbcMyCommand = OdbcMyConnection.CreateCommand();
OdbcMyCommand.CommandText = "SELECT IS_FREE_LOCK('OdbcExecuter')";
int nStatus = 0;
while (!bStatus)
{
bStatus = Convert.ToBoolean(OdbcMyCommand.ExecuteScalar());
if (bStatus) break;
ldots.Text += ".";
Thread.Sleep(400);
Application.DoEvents();
}
try
{
OdbcMyCommand.CommandText = "SELECT GET_LOCK('OdbcExecuter',60)";
nStatus = Convert.ToInt32(OdbcMyCommand.ExecuteScalar());
if (nStatus == 1) bStatus = true;
else bStatus = false;
}
catch (OdbcException e)
{
MessageBox.Show(this, e.ToString());
bStatus = false;
}
OdbcMyCommand.Dispose();
OdbcMyConnection.Close();
return bStatus;
}
private bool ReleaseTables()
{
OdbcConnection OdbcMyConnection = new OdbcConnection(connstring);
OdbcMyConnection.Open();
bool bStatus = false;
OdbcCommand OdbcMyCommand = OdbcMyConnection.CreateCommand();
try
{
int nStatus = 0;
OdbcMyCommand.CommandText = "SELECT RELEASE_LOCK('OdbcExecuter')";
nStatus = Convert.ToInt32(OdbcMyCommand.ExecuteScalar());
if (nStatus == 1) bStatus = true;
else bStatus = false;
}
catch (OdbcException e)
{
MessageBox.Show(this, e.ToString());
bStatus = false;
}
OdbcMyCommand.Dispose();
OdbcMyConnection.Close();
return bStatus;
}
The public functions:
public void AddQuery(string sQuery)
{
if (nCommands > 0)
QueryCollection = (string[])ResizeArray(QueryCollection,
QueryCollection.Length + 1);
QueryCollection[nCommands] = sQuery;
nCommands++;
}
public bool ExecuteQueries()
{
bool bStatus = false;
if (!this.Focus())
{
this.TopMost = true;
this.ShowInTaskbar = false;
this.Show();
}
OdbcConnection OdbcMyConnection = new OdbcConnection(connstring);
OdbcMyConnection.Open();
OdbcCommand OdbcMyCommand = OdbcMyConnection.CreateCommand();
OdbcTransaction transact =
OdbcMyConnection.BeginTransaction(IsolationLevel.ReadCommitted);
OdbcMyCommand.Transaction = transact;
if (LockTables())
{
try
{
for (int nQuerys = 0; nQuerys < nCommands; nQuerys++)
{
OdbcMyCommand.CommandText = QueryCollection[nQuerys];
OdbcMyCommand.ExecuteNonQuery();
}
transact.Commit();
bStatus = true;
}
catch (Exception cmex)
{
try
{
transact.Rollback();
}
catch (OdbcException ex)
{
MessageBox.Show(this, ex.ToString());
}
MessageBox.Show(this, cmex.ToString());
bStatus = false;
}
finally
{
OdbcMyCommand.Dispose();
OdbcMyConnection.Close();
}
}
ReleaseTables();
this.Hide();
return bStatus;
}
public void CleanQueries()
{
QueryCollection.Initialize();
QueryCollection = new string[1];
nCommands = 0;
}
OK, this concludes our coding for the OdbcExecuter
class. If you want to include it on your projects, be free to download the class and implement.