Updating tables with column names containing # symbols using OleDbCommandBuilder in C# - c#

Greetings great SO comrades;
I'm trying to use this code to make changes to a SQL Server database:
adapter = new OleDbDataAdapter(
Db.GetRecordSql(table.Name, recordId), Db.Connection);
OleDbCommandBuilder cmd = new OleDbCommandBuilder(adapter);
DataSet ds = new DataSet();
adapter.Fill(ds);
Then later, when saving changes made to a DataRow:
adapter.Update(new DataRow[] { row });
It works exactly the way I want it to work. The DB operations are all very simple, and the app supports multiple database formats, so this is the method that suits the task.
My problem is that this method fails when the row contains a column with an # sign in its name. The database schema prefixes column names with an # sign to denote private meta data, such as creation/modification dates and checksums.
When a column name contains an # sign, the Update method throws an OleDbException:
Must declare the scalar variable #created
Great. Now what?
Seriously, I've googled this thing to death. I know it's a bit unusual to include an # symbol in a column name, but that's the hand I've been dealt.
Any ideas? Pretty please? :)

You should be able to specify the QuotePrefix and QuoteSuffix characters in the command builder:
cmd.QuotePrefix = "[";
cmd.QuoteSuffix = "]";
After doing that, the command it builds will have brackets around all the names (columns and tables). And I suppose it goes without mentioning, but be sure that the prefix and suffix values you use are valid for the underlying database. For example, for some databases, it might be necessary to use double quotes instead of brackets.

Related

Cannot remove this column, because it is part of an expression

I have a datatable and I am masking one column by adding new column name as MASKEDSSN.
It has been masked. But i need to Remove Old Column name SSN. While Removing it throws an error as
Cannot remove this column, because it is part of an expression:
MaskedSSN = 'XXX-XX-'+SUBSTRING(CONVERT(SSN, System.String),6,4).
Code:
DataTable employeeTable = new DataTable();
employeeTable.Rows.Add("123455789");
employeeTable.Rows.Add("123447789");
employeeTable.Rows.Add("823456719");
employeeTable.Columns.Add("SSN");
int index = employeeTable.Columns["SSN"].Ordinal;
employeeTable.Columns.Add("MaskedSSN", typeof(string));
employeeTable.Columns["MaskedSSN"].Expression = "'XXX-XX-
'+SUBSTRING(CONVERT(SSN, System.String),6,4)";
DataTable newsss = new DataTable();
newsss = employeeTable.Copy();
newsss.AcceptChanges();
newsss.Columns.RemoveAt(index);
newsss.Columns.Remove("SSN");
You are using Expression syntax to build MaskedSSN
employeeTable.Columns["MaskedSSN"].Expression = "'XXX-XX-
'+SUBSTRING(CONVERT(SSN, System.String),6,4)";
If you make masking manually with AddRow, you can delete old SSN Column.
Edit
Func<string, string> MaskingFnc = (string ssnParam) => string.Format("XXX-XX-{0}", ssnParam.Substring(4,6));
DataTable employeeTable = new DataTable();
employeeTable.Columns.Add("SSN")
employeeTable.Columns.Add("SSNMasked")
employeeTable.Rows.Add("123455789", MaskingFnc("123455789"));
employeeTable.Rows.Add("123447789", MaskingFnc("123447789"));
employeeTable.Rows.Add("823456719", MaskingFnc("823456719"));
Expressions, or computed columns, relies on the source column to have the data in, because it is referencing the data, it doesn't COPY the data and then mask it.
So if your original column data changes, the new column will automatically have the same value.
When you understand this dependency, you will realize that you can't just remove the source column, because if you do, you will have a null reference exception happening. Think of it as excel spreadsheet. Column A has a value, Column B uses Column A's value to determine a percentage (or show it in a currency format). If you delete Column A, Columb B will immediately get an error (#REF! or something)
Your question on CodeProject has more detail, which would be appreciated on StackOverflow too: https://www.codeproject.com/Questions/1272445/Cannot-remove-this-column-because-it-is-part-of-an
In there, you show you try to copy the table, and then remove the column from it, while still having the expression, which results in an error.
Hopefully my explanation highlights the dependency between a column and a computed column/expression.
I would suggest formatting the data in the front-end (that's why we have front-end), or, if it's part of an API, format it in the SQL output.
Any input can also be masked so that data is inserted correctly BEFORE having to read it out anywhere.
You can mask manually using string.Format (note, below might not compile, I leave it to you to figure out)
string result = string.Format("XXX-XX-{0}", SSNColumnValue.Substring(4,6));
Hope this helps guide you in the right direction

ORA-01036: illegal variable name/number when running query through C#

I am trying to use ALTER USER query for Oracle database using OracleCommand in C# in the following code. It creates the query if the values for Username and password are not empty strings. But I get an error "ORA-01036: illegal variable name/number" when ExecuteNonQuery() is executed.
string updateQuery = "ALTER USER :user IDENTIFIED BY :password";
connection = new OracleConnection(LoginPage.connectionString);
connection.Open();
OracleCommand cmd = new OracleCommand(updateQuery, connection);
cmd.Connection = connection;
for(int i=0;i<usersList.Count;i++)
{
if (!(selectedUsersArray[i].Equals("")) && !passwordArray[i].Equals(""))
{
OracleParameter userName = new OracleParameter();
userName.ParameterName = "user";
userName.Value = selectedUsersArray[i];
OracleParameter passwd = new OracleParameter();
passwd.ParameterName = "password";
passwd.Value = passwordArray[i];
cmd.Parameters.Add(userName);
cmd.Parameters.Add(passwd);
cmd.Prepare();
cmd.ExecuteNonQuery();
}
}
Could you please suggest what is wrong with my implementation?.
The root cause
In Oracle you have three kinds of SQL statements (and additionally there are PL/SQL blocks):
Statements in the Data Definiton Language (DDL). These statements modify the structure of the database. They begin usually with the verbs "ALTER" or "CREATE"
Statements in the Data Modification Langugage (DML). There statements modify the content inside of tables, leaving the structure of each table unmodified. These statements usually begin with "INSERT", "MERGE" or "DELETE".
Statements in what I call "query language" (there seems to be no canonical name for these). This statements start with the verb "SELECT".
Bind variables in Oracle are only allowed in some special places in DML and query statements. You are trying to use bind variables in a places where they are not allowed. Hence the error.
Solution
Build your statement without bind variables. Build the complete query string instead using string concatenation.
If you want to sanitize the input before concatenating the string, use the DBMS_ASSERT package.
Background
Bind variables can only be used when Oracle can build a query plan without knowing the value of the variable. For DDL statements, there is no query plan. Hence bind variables are not allowed.
In DML and query statements, bind variables are only allowed, when they are used inside a tuple (regarding the underlying set theory), i.e. when the value will be compared with the value in a table or when the value will be inserted in a table. They are not allowed to change the structure of the execution plan (e.g. to change the target table or to change the number of comparisons).
Just for others getting this error and looking for info on it, it is also thrown if you happen to pass a binding parameter and then never use it. I couldn't really find that stated clearly anywhere but had to prove it through trial and error.
I just spent several days checking parameters because I have to pass 60 to a stored procedure. It turns out that the one of the variable names (which I load into a list and pass to the Oracle Write method I created) had a space in the name at the end. When comparing to the variables in the stored procedure they were the same, but in the editor I used to compare them, I didnt notice the extra space. Drove me crazy for the last 4 days trying everything I could find, and changing even the .net Oracle driver. Just wanted to throw that out here so it can help someone else. We tend to concentrate on the characters and ignore the spaces. . .
You defined one oracleCommand but used it in 'for'.
it means you are adding parameter with the same name to one OracleCommand.
you should use cmd.Parameters.clear() to refresh your parameters.
for(int i=0;i<usersList.Count;i++)
{
if (!(selectedUsersArray[i].Equals("")) && !passwordArray[i].Equals(""))
{
cmd.Parameters.clear();//Add this line
OracleParameter userName = new OracleParameter();
userName.ParameterName = "user";
userName.Value = selectedUsersArray[i];
OracleParameter passwd = new OracleParameter();
passwd.ParameterName = "password";
passwd.Value = passwordArray[i];
cmd.Parameters.Add(userName);
cmd.Parameters.Add(passwd);
cmd.Prepare();
cmd.ExecuteNonQuery();
}
}
The Oracle error ORA-01036 means that the query uses an undefined variable somewhere. From the query we can determine which variables are in use, namely all that start with #. However, if you're inputting this into an advanced query, it's important to confirm that all variables have a matching input parameter, including the same case as in the variable name, if your Oracle database is Case Sensitive.
This error happens when you are also missing cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("GUSERID ", OracleType.VarChar)).Value = userId;
I was having eight parameters and one was with space at the end as shown in the above code for "GUSERID ".Removed the space and everything started working .
I was having the same problem in an application that I was maintaining, among all the adjustments to prepare the environment, I also spent almost an hour banging my head with this error "ORA-01036: illegal variable name / number" until I found out that the application connection was pointed to an outdated database, so the application passed two more parameters to the outdated database procedure causing the error.
You cannot pass user/table name to pl/sql with a parameter. You can create a procedure and build sql and then execute immediately to achieve that.
I have faced same problem ... For the problem is like this, I am calling the PRC inside cpp program and my PRC taking 4 arguments but while calling I used only 1 arguments so this error came for me.
Begin Example_PRC(:1); End; // this cause the problem
Begin Example_PRC(:1,:2,:3,:4); End; // this is the solution
I had the same issue today when using Python module cx_Oracle. In my case, the root cause was an invalid variable name.
Example: SELECT * FROM DATA WHERE KEY IN (:_0, :_1, ...)
When I changed _0 to var0, it worked fine.
From this blog post, I found these rules for variable names:
Must start with a letter
Maximum size is limited to 30 letters
Cannot contain whitespace characters
Can contain dollar sign ('$'), underscore ('_') and hash sign ('#')
Is case-insensitive
I had the same problem, was learning connection to oracledb.
previous code-
SELECTALLCANDIDATES = "Select * from candidate_master";
data= await connection.execute(SELECTALLCANDIDATES, {autoCommit:true})
Removed the {autoCommit:true} and it started working fine.Correct code-
SELECTALLCANDIDATES = "Select * from candidate_master";
data= await connection.execute(SELECTALLCANDIDATES)
Still don't know why but it works.
Check your named variables match, I had the same problem, I had a spelling mistake/typo in one of my parameters

Escaping various characters in C# SQL from a variable

I'm working a C# form application that ties into an access database. Part of this database is outside of my control, specifically a part that contains strings with ", ), and other such characters. Needless to say, this is mucking up some queries as I need to use that column to select other pieces of data. This is just a desktop form application and the issue lies in an exporter function, so there's no concern over SQL injection or other such things. How do I tell this thing to ignore quotes and such in a query when I'm using a variable that may contain them and match that to what is stored in the Access database?
Well, an example would be that I've extracted several columns from a single row. One of them might be something like:
large (3-1/16" dia)
You get the idea. The quotes are breaking the query. I'm currently using OleDb to dig into the database and didn't have an issue until now. I'd rather not gut what I've currently done if it can be helped, at least not until I'm ready for a proper refactor.
This is actually not as big problem as you may see it: just do NOT handle SQL queries by building them as plain strings. Use SqlCommand class and use query parameters. This way, the SQL engine will escape everything properly for you, because it will know what is the code to be read directly, and what is the parameter's value to be escaped.
You are trying to protect against a SQL Inject attack; see https://www.owasp.org/index.php/SQL_Injection.
The easiest way to prevent these attacks is to use query parameters; http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter.aspx
var cmd = new SqlCommand("select * from someTable where id = #id");
cmd.Parameters.Add("#id", SqlDbType.Int).Value = theID;
At least for single quotes, adding another quote seems to work: '' becomes '.
Even though injection shouldn't be an issue, I would still look into using parameters. They are the simpler option at the end of the day as they avoid a number of unforeseen problems, injection being only one of them.
So as I read your question, you are building up a query as a string in C#, concatenating already queried column values, and the resulting string is either ceasing to be a string in C#, or it won't match stuff in the access db.
If the problem is in C#, I guess you'll need some sort of escaping function like
stringvar += escaped(columnvalue)
...
private static void escaped(string cv) as string {
//code to put \ in front of problem characters in cv
}
If the problem is in access, then
' escapes '
" escapes "
& you can put a column value containing " inside of '...' and it should work.
However my real thought is that, the SQL you're trying to run might be better restructured to use subqueries to get the matched value(s) and then you're simply comparing column name with column name.
If you post some more information re exactly what the query you're producing is, and some hint of the table structures, I'll try and help further - or someone else is bound to be able to give you something constructive (though you may need to adjust it per Jet SQL syntax)

C# SqlDataAdapter.Fill giving error about data conversion when passed datatable parameter

I'm trying to fill a datatable using a SqlDataAdapter in C#. I'm not very familiar with the objects, and am basically working off a template of someone else's code to try to figure out how it works. Here's the basic form.
SqlCommand command = new SqlCommand(#"SELECT * FROM tblEmployees WHERE Name = " + firstSSN,connection);
SqlDataAdapter adapter = new SqlDataAdapter(command.CommandText.ToString(), connection.ConnectionString.ToString());
SqlCommandBuilder cmdBuilder = new SqlCommandBuilder(adapter);
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
adapter.Fill(table);
And that works fine on their form. I tried doing the same with mine, but got an error about trying to convert a nvarchar to a column of data type int. I looked through MSDN and tried the following: 1) Adding the columns to the DataTable with the appropriate names/types/primary keys from tblEmployees. 2) Adding the TableMapping to the DataAdapter, though I'm not 100% sure I have the syntax on this part right. I do:
adapter.TableMappings.Add("work", "dbo.tblEmployees");
for that. The DataTable is named "work", but I'm unsure if I have the syntax right, I put in the table name as it appears in SQL Server Management Studio but don't know how I test if it's linking up correctly.
Thanks for any help you can provide. I've been beating my head on this to the point that I'm on the verge of approaching my goal an entirely different way and throwing away what I have.
At first glance, when looking at the first line of your code, look where firstSSN is:
#"Select * From tblEmployees WHERE Name = " + firstSSN
I would imagine that 'Name' is the nvarchar field that the error message is referencing, and if firstSSN is an integer value only, try putting '' marks around firstSSN like this:
#"Select * From tblEmployees WHERE Name = '" + firstSSN + "'"
Otherwise, make sure that the type of the field "Name" matches the type of the parameter you are passing into your command. This is most likely just a data type issue.
One recommendation I have for you - I just started experimenting with LINQ the other day, and find it pretty handy to use for pulling out, manipulating, and filtering data into an easy to use record set. There's all kinds of documentation available on how to execute queries with LINQ, so have a look if you have a few minutes. Hope this helps.

Opening an Excel file in c#

So there are a lot of questions regarding this method on SO, but none seem to answer my question. I firstly had an issue with the connectionstring (although it seems to work in other areas of my code correctly). This was resolved easily.
Now the issue is with a simple SELECT query via a OLEDBCommand (Text) that keeps popping up the following error?
"SELECT [Opportunity#],[BidManager],[Prob %],[Opportunity_Stage].[Opportunity_Status],[Term],[Sign Date] FROM [Sheet1$];"
No value given for one or more required parameters.
but their are no parameters????
Checked and double checked the columns names, but to no avail. Also tried removing the special characters from the column names, but still the same exception.
I'd suggest trying to run SELECT * FROM [Sheet1$] that way you'll know pretty certain if it's a column issue or an issue with the rest of the code.
Also, I can't check at the very moment, but are you sure there should be a ; after the select statement, isn't that just when you want to execute multiple statements?
OleDbCommand requires two parameters, the command string you are trying to execute and the OleDbConnection itself. Are you calling it correctly?
Dim myConnection As New OleDbConnection(myConnString)
OleDbCommand myCommand = new OleDbCommand(mySelectQuery,myConnection);
I've had this error with an OleDb command when my column names were incorrect.
"No value given for one or more required parameters."
I assume that the database interprets any columns names that it cannot find as parameters

Categories