I am generating SQL code for different types of databases. To do that dynamically, certain parameters of the SQL script are stored in variables.
One such stored parameter is the comparison expression for certain queries.
Lets say I have a Dogs table with a Name, DateOfBirth and Gender columns, then I have comparison expressions in a variable such as:
string myExpression = "Gender=1";
string myExpression2 = "Gender=1 AND Name='Bucky'";
I would build the following SQL string then:
string mySqlString = "SELECT * FROM "dbo"."Dogs" WHERE " + myExpression;
The problem is, that for Oracle syntax, I have to quote the column names (as seen at dbo.Dogs above). So I need to create a string from the stored expression which looks like:
string quotedExpression = "\"Gender\"=1";
Is there a fast way, to do this? I was thinking of splitting the string at the comparison symbol, but then I would cut the symbol itself, and it wouldn't work on complex conditions either. I could iterate through the whole string, but that would include lot of conditions to check (the comparison symbol can be more than one character (<>) or a keyword (ANY,ALL,etc.)), and I rather avoid lots of loops.
IMO the problem here is the attempt to use myExpression / myExpression2 as naked SQL strings. In addition to being a massive SQL-injection hole, it causes problems like you're seeing now. When I need to do this, I treat the filter expression as a DSL, which I then parse into an AST (using something like a modified shunting yard algorithm - although there are other ways to do it). So I end up with
AND
=
Gender
1
=
Name
'Bucky'
Now I can walk that tree (visitor pattern), looking at each. 1 looks like an integer (int.TryParse etc), so we can add a parameter with that value. 'Bucky' looks like a string literal (via the quotes), so we can add a string-based parameter with the value Bucky (no quotes in the actual value). The other two are non-quoted strings, so they are column names. We check them against our model (white-list), and apply any necessary SQL syntax such as escaping - and perhaps aliasing (it might be Name in the DSL, but XX_Name2_ChangeMe in the database). If the column isn't found in the model: reject it. If you can't understand an expression completely: reject it.
Yes, this is more complex, but it will keep you safe and sane.
There may be libraries that can already do the expression parsing (to AST) for you.
Related
I am getting incorrect syntax error
sYNTAX ERROR Unclosed quotation mark after the character string ' AND ID=''.'
Parameters, basically. They solve problems with quotes and other special symbols, SQL injection problems, and a range of i18n/l10n problems. They're also more efficient due to query plan reuse.
Now, ADO.NET doesn't make it trivial to add parameters, so that's where tools like "Dapper" come in. You also probably want to use a "reader" rather than ExecuteScalar, which can only read one column and one row, but that's a separate issue.
If we did this with "Dapper":
int x = (int)connselect.ExecuteScalar(#"
SELECT * FROM PrintedCards
WHERE Card_Id=#cardId AND Name=#name
-- etc, only 2 shown here
", new { cardId = r["Card_Id"], name = r["Name"] } // <== the parameters
);
If you actually intended to read objects, this would be .Query<T> (for some T) rather than .ExecuteScalar
In our C# desktop-application we generate a lot of dynamic sql-queries. Now we have some troubles with single quotes in strings. Here's a sample:
INSERT INTO Addresses (CompanyName) VALUES ('Thomas' Imbiss')
My question is: How can I find and replace all single quotes between 2 other single quotes in a string? Unfortunately I can't replace the single quotes when creating the different queries. I can only do that after the full query is created and right before the query gets executed.
I tried this pattern (Regular Expressions): "\w\'\w"
But this pattern doesn't work, because after "s'" there's a space instead of a char.
I am sorry to say, there is no solution in approach you expect.
For example, have these columns and values:
column A, value ,A',
column B, value ,B',
If they are together in column list, you have ',A',',',B','.
Now, where is the boundary between first and second value? It is ambiguous.
You must take action when creating text fields for SQL. Either use SQL parameters or properly escape qoutes and other problematic characters there.
Consider showing the above ambiguous example to managers, pushing the whole problem back as algorithmically unsolvable at your end. Or offer implementing a guess-work and ask them whether they will be happy if content of several text fields can get mixed in some cases like above one.
At time of SQL query creation, if they do not want to start using SQL parameters, the solution for enquoting any input string is as simple as replacing:
string Enquote(string input)
{
return input.All(c => Strings.AscW(c) < 128) ? "'" : "N'"
+ input.Replace("'", "''")
+ "'"
}
Of course, it can have problem with deliberately malformed Unicode strings (surrogate pairs to hide ') but it is not normally possible to produce these strings through the user interface. Generally this can be still faster than converting all queries to versions with SQL parameters.
I have been developing an application that one of it's responsability is provide to user an page that it's possible to write math expression in EXCEL WAY.
It is an application in ASP.NET MVC, and it's use the SpreadSheetGear library to EXECUTE excel expression.
As it's show below, The page has an texarea to write expression and two button on the right. The green one is for VALIDATE THE EXPRESSION and the red one is for clean textarea.
A,B,C are parameter, that application will replace for values. Notice that it is not possible to know the parameter data type. I mean, if I write a concatenate function, It is necessary that user use double quotes (") to delimitate string. For example
CONCATENATE("A","B") thus, is necessary that user KNOW functions parameters and its correlate data types.
My main issue is how to validate the expression?
SpreadSheetGear there isn't any method to perform this validation.
The method spreadsheetgear provides to perform an formula is:
string formula = "{formula from textarea}"
worksheet.EvaluateValue(formula)
and it's expect and string.
As I don't know what formula user will write, or how many parameters this formula has and what are the parameters data type, it's kind difficult to validate.
Now my question is?
How could I validate the expression?
I think in an alternative: Provide to user and page with textbox for each parameter in the expression. The user will be able to provide some data and validate the RESULT of formula. If the sintaxe of formula is wrong the application throw an exception.
It would be a good solution, but for each "PROCESS" that user will interact to, He'll write 10, 15 formulas, and maybe it would be little painful.
Anyone could provide me an Good solution for that?
Thank you!
https://sites.google.com/site/akshatsharma80/home/data-structures/validate-an-arithmetic-expression
refer this site for validation
This is a very late response but I have been working on expression evaluators in Excel with VBA for a while and I might shed some light. I have three solutions to try but all have limitations.
1) Ask the user to put a '$' after a variable name to signify a string (or some other unique character). Drawback is that it is not as simple as typing a single letter for a variable.
2) Assume all variables entered are double precision. Then change the variable to strings in all combinations until one combination works. Could be very time consuming to try all the combinations if the user enters lots of individual variables.
3) Assume all variables entered are double precision. But then have a list in your program of functions that require strings for parameters. Then you could parse the expression, lookup the functions in your list and then designate the parameters that require string input with a string signifier (like in step 1). This will not account for user defined functions.
Now to test out the function, replace all the numeric variables with '1' and all the string variables with "a", then EvaluateValue. If you get a result or an error signifying a calculation error, it is good.
BTW, in order to parse the expression, I suggest the following method. I do not know C#, only VB, so I will only talk in general terms.
1) Take your expression string and do a search and replace of all the typical operators with the same operator but with a backslash ("\") in front and behind the operator (you can use any other character that is not normally used in Excel formulas if you like). This will delineate these operators so that you can easily ignore them and split up your expression into chunks. Typically only need to delineate +,-,/,*,^,<,>,= and {comma}. So search for a "+" and replace it with a "\+\" and so on. For parenthesis, replace "(" and ")" with "(\\" and "\\)" respectively.
So your sample formula "SUM(A, SQRT(B, C)) * PI()" will look like this:
"SUM(\\A\,\ SQRT(\\B\,\ C\\)\\) \*\ PI(\\\\)"
You can also clean up the string a bit more by eliminating any spaces and by eliminating redundant backslashes by replacing every three consecutive backslashes with a single one (replace "\\" with "\").
2) In Visual Basic there is a command called 'Split' that can take a string like this and split it into a one dimensional array using a delimiter (in this case, the backslash). There must be an equivalent in C# or you can just make one. Your array will look like this: "SUM(", "", "A", ",", "SQRT(", "", "B", etc.
Now iterate through your array, starting at the first element and then skipping every other element. These elements will either be a number (a numeric test), a variable, a function (with have a "(" at the end of it), a parenthesis or blank.
Now you can do other checks as you need and replace the variables with actual values.
3) When you are done, rejoin the array back into a string, without any delimiters, and try the Evaluate function.
I am trying to read value from DB using c#.
The query string contains multiple single quotes - such as: Esca'pes' (the query strings are being read from a text file)
So, I wanted to replace all the single quotes with two single quotes before forming the SQL query. My code is as below:
if (name.Contains('\''))
{
name = name.Replace('\'','\''');
}
How to fix this?
Use strings, not char literals.
name = name.Replace("'", "''");
However it sounds like you're concatenating SQL strings together. This is a huge "DO NOT" rule in modern application design because of the risk of SQL injection. Please use SQL parameters instead. Every modern DBMS platform supports them, including ADO.NET with SQL Server and MySQL, even Access supports them.
name = name.Replace("'","''");
On an unrelated note, you're concatenating strings for use in SQL? Try parameters instead, that's what they're meant for. You're probably making it harder than it needs to be.
Since you want to replace a single character with two characters, you need to use the String overload of Replace
if (name.Contains('\''))
{
name = name.Replace("'","''");
}
(Note: single quotes don't require escaping in Strings like they do in character notation.)
I have a database here with certain rules I need to apply to a a bunch of Strings, they're expressions that can occur within the Strings. They are expressed like
(word1 AND word2) OR (word3)
I can't hardcode those (because they may be changed in the database), so I thought about programmatically turning those expressions into Regex patterns.
Has anybody done such a task yet or has an idea on how to do this the best way?
I'm not wuite sure about how to deal with more complex expressions, how to take them apart and so on.
Edit: I'm using C# in VisualStudio / .NET.
The data is basically directory paths, a customer wants to get their documents organized, so the String I'm having are paths, the expressions in the DB could look like:
(office OR headquarter) AND (official OR confidential)
So if the file's directory path contains office and confidential, it should match.
Hope this makes it clearer.
EDIT2:
Heres some dummy examples:
The paths could look like:
c:\documents\official\johnmeyer\court\out\letter.doc
c:\documents\internal\appointments\court\in\september.doc
c:\documents\official\stevemiller\meeting\in\letter.doc
And the expressions like:
(meyer or miller) AND (court OR jail)
So this expression would match the 1st path/ file, but not the 2nd and 3rd one.
No answer, but a good hint:
The expressions you have are actual trees constructed by the parentheses. You need a stack machine to parse the text into a (binary) tree structure, where each node is an AND or OR element and the leaves are the words.
Afterwards, you can simply construct your regex in whatever language you need by walking the tree using depth first search and adding prefix and suffix data as needed before/after reading the subtree.
Consider an abstract class TreeNode having a method GenerateExpression(StringBuilder result).
Each actual TreeNode item will be either an CombinationTreeNode (with a CombinationMode And/Or) or an SearchTextTreeNode (with an SearchText property).
GenerateExpression(StringBuilder result) for CombinationTreeNode will look similar like that:
result.Append("(");
rightSubTree.GenerateExpression(result);
result.Append(") " + this.CombinationMode.ToString() + " (");
rightSubTree.GenerateExpression(result);
result.Append(")");
GenerateExpression(StringBuilder result) for SearchTextTreeNode is much easier:
result.Append(this.SearchText);
Of course, your code will produce a regular expression instead of the input text, as mine does.