Is SQLDataReader slower than using the command line utility sqlcmd? - sqldatareader

I was recently advocating to a colleague that we replace some C# code that uses the sqlcmd command line utility with a SqlDataReader. The old code uses:
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo("cmd", "/c " + sqlCmd); wher sqlCmd is something like
"sqlcmd -S " + serverName + " -y 0 -h-1 -Q " + "\"" + "USE [" + database + "]" + ";+ txtQuery.Text +"\"";\
The results are then parsed using regular expressions. I argued that using a SQLDataReader woud be more in line with industry practices, easier to debug and maintain and probably faster. However, the SQLDataReader approach is at least the same speed and quite possibly slower. I believe I'm doing everything correctly with SQLDataReader. The code is:
using (SqlConnection connection =
new SqlConnection())
{
try
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString);
connection.ConnectionString = builder.ToString(); ;
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// do stuff w/ reader
reader.Close();
}
catch (Exception ex)
{
outputMessage += (ex.Message);
}
}
I've used System.Diagnostics.Stopwatch to time both approaches and the command line utility (called from C# code) does seem faster (20-40%?). The SqlDataReader has the neat feature that when the same code is called again, it's lightening fast, but for this application we don't anticipate that.
I have already done some research on this problem. I note that the command line utility sqlcmd uses OLE DB technology to hit the database. Is that faster than ADO.NET? I'm really suprised, especially since the command line utility approach involves starting up a process. I really thought it would be slower.
Any thoughts?
Thanks,
Dave

I think SqlDataReader is slower than sqlcmd because making a SqlDataReader not only fetches the data but also gets the database schema info, and the sqlcmd gets the data only.
You can get a column name with a datareader like this:
for (int i = 0; i < reader.FieldCount; i++)
{
Console.WriteLine(reader.GetName(i));
}
Sometimes performance is not important, security is more important.
But I don't know which is more secure, maybe SqlDataReader is.
I am a Chinese, so maybe my word is incorrect for the grammer, sorry.

Related

oracleDatareader.ExecuteReader() not returning any data

I have written a code in ASP.NET to fetch data from Oracle database. The code returns data from locally hosted Oracle DB but when I am pointing towards the remote OracleDB, nothing comes. However, if I run same query on the remote DB using SQL Developer Tool, it works fine.
I have debugged my code for right SQL statement and it is absolutely correct.
Following is my code snippet
using (Oracle.DataAccess.Client.OracleConnection con = new
Oracle.DataAccess.Client.OracleConnection())
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["ca_eFormsVSED"].ConnectionString;
con.Open();
// query for fetch username and market
String sql = "a valid query"
Oracle.DataAccess.Client.OracleCommand cmd = new Oracle.DataAccess.Client.OracleCommand(sql, con);
cmd.CommandType = CommandType.Text;
if (con.State == ConnectionState.Open)
{
Oracle.DataAccess.Client.OracleDataReader dr = cmd.ExecuteReader();
}
if (dr.Read())
{
//Do Something
}
}
Please suggest how to make it work.
I got the solution of this problem and it may help some one else. If you are 100% sure that code is correct and current SQL statement returns data from database, then check carefully your database tables have dependency or not. Remove existing tables and import new data again and it works fine for me.

Windows Search SQL: Semicolon in LIKE statement causes exception (E_FAIL 0x80004005)

I am querying the windows search engine about some documents in my ASP.NET web application.
I'm looking for all documents which title contains the string "; IT" (besides other conditions, stripped from the following example).
I'm going through ADO.NET, so my code looks like this one (stripped some unimportant details):
var connString = "Provider=Search.CollatorDSO;" +
"Extended Properties='Application=Windows';";
var conn = new OleDbConnection(connString);
conn.Open();
StringWriter wSql = new StringWriter();
wSql.WriteLine("SELECT System.Title, System.Filename, System.Keywords, " +
"System.Size, System.ItemPathDisplay, System.ItemUrl, " +
"System.Search.Rank, System.DateCreated, System.DateModified " +
"FROM SYSTEMINDEX WHERE System.Title LIKE '%; IT%'");
var cmd = new OleDbCommand(wSql.ToString(), conn);
var adapter = new OleDbDataAdapter(cmd);
var result = new DataSet();
adapter.Fill(result, "doc"); // <== HERE THE RUNTIME EXPLODES
When i run this code, an exception is thrown at the last line, with code "E_FAIL 0x80004005". If i remove the semicolon from the LIKE statement, all works like a charm, but obviously i do not have the expected results, since i really really need only documents in which the title correspond to the given string.
I tried searching for reserved characters and/or escaping in Windows Search SQL, but without luck.
Any idea?
Thanks and regards,
Claudio
I found that the Windows Search API doesn't support the Like operator.

Securing data before update

I have a few text boxes that on my page that can add data to my database. What I'm looking for is how to actually make it more secure. The basic error checking of empty text boxes I know how to check. What I'm really searching for is bad data being saved or special characters like " ' " or " - ". Its a simple application only myself and maybe two other people will use it but still want to make sure learning and coding correctly. Any suggestions. This is my save button.
Here is my code:
try
{
OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=H:\Databases\AddressBook.mdb");
conn.Open();
DataSet ds = new DataSet();
string cmd = "SELECT * FROM tblAddressBook";
OleDbDataAdapter da = new OleDbDataAdapter(cmd, conn);
da.Fill(ds, "Display");
DataRow newRow = ds.Tables["Display"].NewRow();
newRow[1] = txtFirstName.Text;
newRow[2] = txtLastName.Text;
newRow[3] = txtEmail.Text;
newRow[4] = txtPhone.Text;
ds.Tables["Display"].Rows.Add(newRow);
OleDbCommandBuilder cb = new OleDbCommandBuilder(da);
cb.DataAdapter.Update(ds.Tables["Display"]);
conn.Close();
GridView1.DataBind();
}
catch (Exception)
{
lblErrorSave.Text = "Your information did not save clear form and try again";
}
Your code as shown is secure, but does have problems.
What your question is about is SQL Injection. This arises where you use dynamic SQL, like so (air code):
string sql = "insert into tableA (cola, colb) values ("
+ "'" + txtBox1.Text + "',"
+ "'" + txtBox2.Text + "')";
...and then go and execute it. Depending on the contents of the text boxes you could have all sorts of things happening. Something like "');drop table tableA;--"
This does not happen when you use a DataSet as above, so that's OK
Hoewever, your code is very inefficient. The first thing you do is pull down the whole of the Address table. If this is any size it will be slow and add a lot of IO, memory, and computation to the procedure.
You are also not checking that the row to be entered is actually a new one, not a modification of an old one or a duplicate. This may or may not be important to your app, but usually is important (dup data can be a real pain). You can amend your read of the Address table to pull down e.g. a row with the same email address (or whatever is unique), and if it gets it then amend with new data as you do above.
However if the data is to be added, then you need to use parameters; Air Code again:
string sql = "insert into table (colA, colB) values (#colA, #colB)";
using (OleDbCommand com = new OleDbCommand(sql, conn))
{
com.Parameters.Add("#colA", txtBox1.Text);
com.Parameters.Add("#colB", txtBox2.Text);
com.ExecuteNonQuery();
}
(Note that different drivers have slightly different syntax on adding Parameters and I'm not sure that the OleDb command supports this syntax, but there will be something close.)
Using Parameters prevents SQL Injection, as the values of the parameters are transported not intermixed in the SQL string and so their content has no effect of the SQL eventually executed.

How to use SQL-Server Stored Procedures?

over the past week or so I've been building an ASP site that connects to a Sql-Server 2008 database. I've never used Stored procedures and I was wondering if anyone could give me some guidance on how to create and how to use them within an ASP method. I'm trying to make the code of the website as simple and elegant as possible. Here's the code I'm trying to change into a stored procedure:
private void ExecuteInsert(string name, string type)
{
SqlConnection conn = new SqlConnection(GetConnectionStringHM());
string sql = "INSERT INTO tblSoftwareTitles (SoftwareName, SoftwareType) VALUES "
+"(#SoftwareName,#SoftwareSystemType)";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
SqlParameter[] param = new SqlParameter[2];
//param[0] = new SqlParameter("#SoftwareID);
param[0] = new SqlParameter("#SoftwareName", SqlDbType.NVarChar, 200);
param[1] = new SqlParameter("#SoftwareType", SqlDbType.Int);
param[0].Value = name;
param[1].Value = type;
for (int i= 0; i < param.Length; i++)
{
cmd.Parameters.Add(param[i]);
}
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg ="Insert Error:";
msg += ex.Message;
throw new Exception(msg);
}
finally
{
conn.Close();
}
}
This is just a Simple insert that takes two parameters from an entry form and inserts them into the database. Any Help with this would be much appreciated as I feel it would be a useful thing to know later on down the line. Thanks in advance!
You should look in to MSDN basics: http://msdn.microsoft.com/en-us/library/bb896274.aspx
You don't need to complicate things using for loop.
try
{
sqlConnection = new SqlConnection(dbConnectionString);
SqlCommand command = new SqlCommand(sql, sqlConnection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#SoftwareName", SqlDbType.NVarChar, 200).Value = SoftwareNameHere;
command.Parameters.Add("#SoftwareType", SqlDbType.Int).Value = SoftwareTypeHere;
sqlConnection.Open();
return command.ExecuteNonQuery();
}
catch (SqlException ex)
{
Console.WriteLine("SQL Error" + ex.Message.ToString());
return 0;
}
finally
{
conn.Close();
}
If you are using .NET 3.5 or above, you can use the USING code block which takes care of the disposal of your resources. I am not entirely sure, but from what I remember this was introduced with .NET 3.5 to replace Try/Finally code block (which required developers to dispose the resources like connection object manually through code).
using (SqlConnection con = new SqlConnection { dbConnectionString })
{
con.Open();
try
{
using (SqlCommand command = new SqlCommand { CommandType = CommandType.StoredProcedure, Connection = con, CommandTimeout = 300, CommandText = "sp_Test" })
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#SoftwareName", SqlDbType.NVarChar, 200).Value = SoftwareNameHere;
command.Parameters.Add("#SoftwareType", SqlDbType.Int).Value = SoftwareTypeHere;
command.ExecuteNonQuery();
}
}
catch(SqlException ex)
{
//ex.ToString message here;
}
}
The answer you're looking for is at this SO post...
https://stackoverflow.com/a/4561443/1246574
The one thing I would improve upon for the accepted answer in that post, is the example in that answer doesn't use any USING statements. It would be better to have the connection and command within USING statements so they are automatically disposed.
Another approach would be to use the Microsoft Enterprise Library for interacting with your SQL Server DB. I think it's easier than using plain old SqlConnection and SqlCommand.
Since your code already uses parameters, you are 90% of the way there. All you have to do is:
Put the insert statement into a stored procedure, keeping the same parameter definitions as the dynamic statement.
Change CommandType.Text to CommandType.StoredProcedure
Change the command text to be just the name of the stored procedure.
Having done some reading on the subject I've come across some useful articles that really do question my need for stored procedures.
This article gives a good Viewpoint on how stored procedures can be more of a hassle than a help and are quite clunky and tedious in terms of coding, debugging ad error reporting.
http://www.codinghorror.com/blog/2004/10/who-needs-stored-procedures-anyways.html
And this article (linked in the one above) gives a good explanation on parametrized, explaining why they are necessary to reduce the risk of sql injections and also raises the point that these parametrized queries are cached in a similar way to procedures, giving them comparable performance gains
http://www.uberasp.net/getarticle.aspx?id=46
I feel that In my situation keeping parametrized sql Queries coded into my ASP pages will be the smartest move as these pages will be stored on a server and accessed by clients. I imagine if this were an application installed on several client machines hard coding the SQL wouldn't be a desirable option and so Stored procedures would be the best way to go (to my knowledge)
A follow Up to Stored procedures verses Parametrized sql can be found here with different links to each side of the argument if those are interested.
http://www.codinghorror.com/blog/2005/05/stored-procedures-vs-ad-hoc-sql.html
Hope this little answer helps out anyone else considering using stored procedures over parametrized SQL and vice-versa

MySQL / ASP.NET Stored Procedures

Hopefully this is not a ServerFault question...
I'm working forward on migrating a project from storing data in XML Serialization to a MySQL database. I'm using the example provided me from a previous question answered yesterday.
Connecting using phpMyAdmin and MySQL Workbench I've created a Stored Procedure called 'sprocOrderSelectSingleItem'. It seems to work well with MySQL for all I can tell. When I run the SHOW CREATE PROCEDURE sprocOrderSelectSingleItem it returns the following:
CREATE DEFINER=username#% PROCEDURE sprocOrderSelectSingleItem(IN orderID INTEGER)
BEGIN SELECT * FROM tblOrders WHERE ID=orderID; END
My cooperative ASP.NET code goes something like this:
public static Order GetItem(int ID)
{
Order objOrder = null;
using (OdbcConnection objConnection = new OdbcConnection(Utils.ApplicationConfiguration.ConnectionString))
{
OdbcCommand objCommand = new OdbcCommand("sprocOrderSelectSingleItem", objConnection);
objCommand.CommandType = CommandType.StoredProcedure;
objCommand.Parameters.AddWithValue("orderID", ID);
objConnection.Open();
using (OdbcDataReader objReader = objCommand.ExecuteReader())
{
if (objReader.Read())
{
objOrder = FillDataRecord(objReader);
}
objReader.Close();
}
objConnection.Close();
}
return objOrder;
}
When I view the page I get the following error message:
ERROR [42000] [MySQL][ODBC 5.1 Driver][mysqld-5.0.77]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sprocOrderSelectSingleItem' at line 1
Really not catching on to what could be missing or going wrong. Are there any additional tests I should/could be running to confirm things are working on the MySQL side? Am I missing a step to pass the Stored Procedure call correctly in ASP.NET? The code breaks at the line of:
using (OdbcDataReader objReader = objCommand.ExecuteReader())
Replacing the line of
OdbcCommand objCommand = new OdbcCommand("sprocOrderSelectSingleItem", objConnection);
with this instead
OdbcCommand objCommand = new OdbcCommand("SELECT * FROM tblOrders WHERE ID=" + ID + ";", objConnection);
and everything works as expected.
Thanks for any help you guys can provide.
Your can run an execute on sprocOrderSelectSingleItem in Mysql directly with the ID parameter.
It will show that your StoredProc run correctly.
Here is a sample code in C# that call a stored proc.
OdbcCommand salesCMD = new OdbcCommand("{ CALL SalesByCategory(?) }", nwindConn);
salesCMD.CommandType = CommandType.StoredProcedure;
OdbcParameter myParm = salesCMD.Parameters.Add("#CategoryName", OdbcType.VarChar, 15);
myParm.Value = "Beverages";
OdbcDataReader myReader = salesCMD.ExecuteReader();
Look at the "Call" in the OdbcCommand and the "?" for the parameter that is later supplied with a value.
Can you try something like below:
OdbcCommand cmd = new OdbcCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "{call LoadCustCliOrders(?,?,?,?)}";
cmd.Parameters.Add("CUST_ID",OdbcType.Int);
cmd.Parameters.Add("CLIENT_ID",OdbcType.Int);
cmd.Parameters.Add("DATE_FROM",OdbcType.Date);
cmd.Parameters.Add("DATE_TO",OdbcType.Date);
...
cmd.Parameters["CUST_ID"].Value = _CustId;
cmd.Parameters["CLIENT_ID"].Value = _ClientId;
cmd.Parameters["DATE_FROM"].Value = _DateFrom;
cmd.Parameters["DATE_TO"].Value = _DateTo;
cmd.ExecuteReader
Are you sure that you are using the same username or user with the same access privileges.
I think you need to add the word "CALL" before the stored proc.
It should be CALL sprocOrderSelectSingleItem and try.

Resources