GetOleDbSchemaTable(OleDbSchemaGuid.Indexes, ...) always returning zero rows access database - vb.net

When querying an Access 2000 database, using:
schemaTable = cn.GetOleDbSchemaTable(OleDbSchemaGuid.Indexes, New Object() {Nothing, Nothing, tableName})
Where cn is a valid and open connection, schemaTable always contains zero rows, despite the tableName specified having many indexes.
This documentation, here http://msdn.microsoft.com/en-us/library/cc668764.aspx suggests that MS Access provides this information.
What gives?

It appears that when retrieving .Indexes the third member of the restrictions array corresponds to the Index name, not the Table name. So to retrieve the indexes for a given table it looks like we need to retrieve all of the indexes (no restrictions) and then filter out the ones we don't want.
The following C# code works for me:
using (OleDbConnection con = new OleDbConnection())
{
con.ConnectionString = myConnectionString;
con.Open();
object[] restrictions = new object[3];
System.Data.DataTable table = con.GetOleDbSchemaTable(OleDbSchemaGuid.Indexes, restrictions);
// Display the contents of the table.
foreach (System.Data.DataRow row in table.Rows)
{
string tableName = row[2].ToString();
if (tableName == "Clients")
{
foreach (System.Data.DataColumn col in table.Columns)
{
Console.WriteLine("{0} = {1}",
col.ColumnName, row[col]);
}
Console.WriteLine("============================");
}
}
con.Close();
}

Related

In ADO.Net, iterating over a loop inside a sql connection is causing error

I am writing a program to maintain an inventory of medicine in our store.
I have a Add to cart list, which opens up the SQL connection and delete 1 quantity from the entire stock where the parameter is #medicine
My addToCart listBox's code looks like this
using (SqlConnection conn = new SqlConnection(cstring))
{
using(SqlCommand cmd = new SqlCommand("Update Medicine set Quantity = Quantity - 1 where Name = #medicine", conn))
{
conn.Open();
foreach(string item in cartMedicine)
{
cmd.Parameters.AddWithValue("#medicine", item);
cmd.ExecuteNonQuery();
}
conn.Close();
listMedicine.Items.Clear();
}
}
Now I want to loop my cartMedicine list to get all the names stored in the listbox one by one. But I am getting the error message that,
The variable name '#medicine' has already been declared. Variable names
must be unique within a query batch or stored procedure.'
How can I use the same logic of giving an Adhoc statement each time for each inventory in my Item's list?
Don't add the parameter over and over again but add it once and then just set its value. "AddWithValue is Evil" anyway.
...
SqlParameter sqlParameter = cmd.Parameters.Add("#medicine", SqlDbType.<data type>, <length>)
foreach (string item in cartMedicine)
{
sqlParameter.Value = item;
cmd.ExecuteNonQuery();
}
...
Replace <data type> and <length> with the proper values for the data type of medicine.quantity in the database.

SQL Injection on Views

We are using 3-Tier Architecture in ASP.Net.
There are 3 Layers
Presentation
Business
Data Access
The Data Access Layer contains the GetData and ExecuteQuery etc function.
What I want to know is that, that want to call the View directly from the Presentation Layer. Is there any chance of SQL injection in calling a view from front-end without using stored procedure?
Presentation Layer (C#)
protected void btnView_Click(object sender, EventArgs e)
{
DL obj = new DL();
DataTable tb = new DataTable();
string query = "select * from ViewTeacher where FID = " + txtName.Text;
tb = obj.GetData(query);
}
DBAccess
public DataTable GetData(string query)
{
DataTable datatable = new DataTable();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = query;
try
{
if (cmd.Connection.State != ConnectionState.Open)
{
cmd.Connection.Open();
}
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(datatable);
}
}
catch (Exception ex)
{
throw new ArgumentException(ex.Message);
}
return datatable;
}
How are you "calling a view"? If you're running an ad-hoc query of:
SELECT <columns> FROM View WHERE ColumnX = 'Y'
and if that query is being constructed using (potentially) hostile input then yes, of course that can be subject to SQL injection - the whole point of injection is that the attacker can change the nature of the query:
SELECT <columns> FROM View WHERE ColumnX = 'Z'
UNION ALL
SELECT name,0,0,0,0 FROM INFORMATION_SCHEMA.TABLES --'
The attacker isn't limited to just the objects that are present in the original query.
The untrustworthy input in the two above queries was:
Y
and
Z'
UNION ALL
SELECT name,0,0,0,0 FROM INFORMATION_SCHEMA.TABLES --
As you are writing the query as follows that takes value from a textbox, 100% there is posibility for sql injection.
string query = "select * from ViewTeacher where FID = " + txtName.Text;
There should be no chance of SQL Injection while calling a view from front end, as views don't take parameters.
reference :
can we pass parameter to a view in sql?

Sql Bulk Copy Cannot access destination table

I'm trying to read data from files and to use bulk copy to insert it in the database table.
When I try to run my code, I get the error: "Cannot Access Denstination Table"
Declaration of FlatTable.
System.Data.DataTable flatTableTempData = new System.Data.DataTable("FlatTable");
DataColumn DistrictColumn = new DataColumn();
DistrictColumn.ColumnName = "DistrictName";
// Create Column 3: TotalSales
DataColumn TownColumn = new DataColumn();
TownColumn.ColumnName = "TownName";
DataColumn FarmerColumn = new DataColumn();
FarmerColumn.ColumnName = "FarmerName";
flatTableTempData.Columns.Add(DistrictColumn);
flatTableTempData.Columns.Add(TownColumn);
flatTableTempData.Columns.Add(FarmerColumn);
This is my code, with the connection string and the insertion using bulk copy:
using (SqlConnection con = new SqlConnection("Data Source=DRTARIQ-PC\\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=TestDB2"))
{
con.Open();
using (SqlBulkCopy s = new SqlBulkCopy(con))
{
s.DestinationTableName = flatTableTempData.TableName;
foreach (var column in flatTableTempData.Columns)
s.ColumnMappings.Add(column.ToString(), column.ToString());
s.BulkCopyTimeout = 500;
s.WriteToServer(flatTableTempData);
}
}
I've encountered the same problem. The table exists, the SQL user has access but SqlBulkCopy cannot access the table. My problem turned out to be I turned off the indexing to try and insert faster (rebuild index after the bulkcopy), but this made the table inaccessible. After I turned the indexing on again it worked, SqlBulkCopy has access to the table.
The table name in WriteToServer method of SqlBulkCopy must be surrounded with [ ] signs.

error in the syntax of cmd parameters

hi guyz in this method i m just adding the values to the db.
temp is a object.
the field value and variables in the object re havin the same name..
dono y this error s comin
plz
help me out...
public virtual void Save_input_parameter_details(Test_Unit_BLL temp )
{
SqlConnection con;
con = new SqlConnection("Data Source=VV;Initial Catalog=testingtool;User ID=sa;Password=sa;");
con.Open();
SqlCommand cmd, cmd2, cmd3;
//try
//{
for (int i = 0; i < temp.No_Input_parameters; i++)
{
cmd2 = new SqlCommand("insert into Input_parameter_details values(#Input_Parameter_name,#Input_Parameter_datatype,#noparams,#class_code", con);
cmd2.Parameters.AddWithValue("#Input_Parameter_datatype", temp.Input_Parameter_datatype[i]);
cmd2.Parameters.AddWithValue("#Input_Parameter_name", temp.Input_Parameter_name[i]);
cmd2.Parameters.AddWithValue("#noparams", temp.No_Input_parameters);
cmd2.Parameters.AddWithValue("#class_code",temp.class_code);
cmd2.ExecuteNonQuery();
}
//}
//catch (Exception ex)
// {
// MessageBox.Show("error"+ex);
// }
}
It may be failing based on the unknown actual sequence of columns its trying to push the data into. You are implying the first X number of columns. You may need to be explicit in your SQL such as :
insert into YourTable ( Fld1, Fld2, Fld3 ) values (#ParmVal1, #ParmVal2, #ParmVal3 );
Then do your parameters.add with values... Additionally, you MAY want to make sure your added parameters are in the same sequence as your SQL statement lists them too.
Do the columns in the table line up with the parameters as you have them listed (1st = input_parameter_name, 2nd = input_parameter_datatype, etc.)?

How do you access data that has been inserted using a ADO.NET transaction?

I'm trying to get the data that has been successfully input into the database via ADO.NET transaction.
Once you've called trans.Commit() there doesn't seem to be a way of getting back the data that has been committed since all identity columns that were created during the transaction are 'virtual' since it is an offline dataset until commit
Many thanks
[EDIT]
Ahh, the problem is, I can't do a reselect as I don't have anything unique to select on other than the identity of the data inserted as part of the transaction.
I can't get the last entered item as this is a multiuser system
Code Sample from a book, not the code in question, but good enough to illustrate what I need:
using System.Data;
using System.Data.SqlClient;
namespace DataAdapterTransaction
{
class Program
{
private static string sqlConnectString = "Data Source=(local);" +
"Integrated security=SSPI;Initial Catalog=AdoDotNet35Cookbook;";
private static string sqlSelect = "SELECT * FROM DataAdapterTransaction";
static void Main(string[] args)
{
object[,] o1 = {{ "1", "field 1.1", "field 2.1" },
{ "2", "field 1.2", "field 2.2" }};
InsertRecords(o1);
object[,] o2 = {{ "3", "field 1.3", "field 2.3" },
{ null, "field 1.4", "field 2.4" }};
InsertRecords(o2);
// Retrieve and output the contents of the table
SqlDataAdapter daRead = new SqlDataAdapter(sqlSelect, sqlConnectString);
DataTable dtRead = new DataTable( );
daRead.Fill(dtRead);
Console.WriteLine("---TABLE DataAdapterTransaction---");
foreach (DataRow row in dtRead.Rows)
Console.WriteLine("Id = {0}\tField1 = {1}\tField2 = {2}",
row["Id"], row["Field1"], row["Field2"]);
Console.WriteLine("\nPress any key to continue.");
Console.ReadKey( );
}
static void InsertRecords(object[,] o)
{
DataTable dt = new DataTable( );
SqlTransaction tran;
SqlConnection connection = new SqlConnection(sqlConnectString);
// Create a DataAdapter
SqlDataAdapter da = new SqlDataAdapter(sqlSelect, connection);
// Stop updating when an error is encountered for roll back.
da.ContinueUpdateOnError = false;
// Create CommandBuilder and generate updating logic.
SqlCommandBuilder cb = new SqlCommandBuilder(da);
// Create and fill a DataTable with schema and data
da.Fill(dt);
// Open the connection
connection.Open( );
// Begin a new transaction and assign it to the DataAdapter
tran = connection.BeginTransaction( );
da.SelectCommand.Transaction = tran;
// Add two rows that will succeed update
for (int i = 0; i <= o.GetUpperBound(0); i++)
{
dt.Rows.Add(new object[] { o[i, 0], o[i, 1], o[i, 2] });
Console.WriteLine(
"=> Row with [Id = {0}] added to DataTable.", o[i, 0]);
}
Console.WriteLine("=> Updating data source using DataAdapter.");
try
{
da.Update(dt);
tran.Commit( );
Console.WriteLine("\nTRANSACTION COMMIT.\n");
}
catch (Exception ex)
{
tran.Rollback( );
Console.WriteLine("\nTRANSACTION ROLLBACK.\n{0}\n", ex.Message);
}
finally
{
connection.Close( );
}
}
}
}
Okay, so what i'm after is just after the transaction commit, I want to get the (scope) identity of the the last inserted row.
My application is successful in updating three dataadapters as part of the transaction, however I am having dificulty looking at the final committed data. I can do a select of the table and see it in there, but that really isn't good enough for production code.
SC
You may just need to reselect the data.
The Books Online says that you should call a Fill again to bring the update your Dataset:
http://msdn.microsoft.com/en-us/library/33y2221y(VS.71).aspx
I generally set my Insert and Update commands so that they they return back a valid DataRow for my DataTable and control the update of the rows in the application that way.
Right so I should do:
// update datatable
da.Update(dt);
// commit updates
tran.Commit( );
// get the updated datatable
da.Fill(dt);
I assume all the identity colums will be updated.
I'll give it a go
SC
I understand you're using identity columns, but is there any natural key in the data you can use to reselect?
(that then raises the question of 'why use identities' but that's a whole other subject...)
Unfortunately no, I cannot reselect using a natural key... I'm stuck with identities... after 8 hours of head banging I contemplated adding a guid field so I could get it to work, but decided that it is against my principles to give up!
SC
This MSDN article describes how to get back identity values when calling the Update method of a DataAdapter.