why do we give >0 in instr function ssrs. The InStr function works without giving the greater than 0 value - reporting-services

why do we give >0 in instr function ssrs.
The InStr function works without giving the greater than 0 value.

Because InStr returns index of first appearance of search string in string that is searched. Index is 1-based, and when string not found, the returned index is lowerbound(string as array of chars) - 1 = 1 - 1 = 0. This is in VB, in C# f.e. it will be 0 - 1 = -1.
When you're using InStr to determine if string is found, you need boolean result, and to get it you use comparison > 0, which returns True when string found and False otherwise.
But, since there is implicit conversion exist between boolean and int, you can use InStr directly, and return value 0 (not found) will be converted to False, while any non-zero value (found) will be converted to True.
Although this is correct and works, this way is less obvious, and taking a look at the code =InStr(...) you can't quickly say, real index needed (integer) or the fact that this index exist (boolean). Finally it's all about code readability and maintainability, don't forget that implicit conversions (especially in not-debuggable SSRS code) may bring you a lot of problems.

Related

Why does a query return a result if the field is numeric and the WHERE clause is a string?

I am running a query on a db table which is returning one record when I expect it to return no records.
SELECT yeargroupID FROM tbl_yeargroup WHERE yeargroup='S' AND schoolID=2.
The yeargroup field is a tinyint field. Thefore the WHERE clause is looking the letter 'S' in the numeric field, so should not find anything. Yet it returns the record with the yeargroup = 0, and yeargroupID=17 (the bottom record in the table)
I'm confused as to why it is returning this record and how to avoid it.
Thanks
This logic, as you have pointed out, is comparing a number and a string:
WHERE yeargroup = 'S'
Handling such situations is an important part of most SQL compilers, and it is well documented. The solution is to implicitly convert values to "conforming" types. This is sad. My preference would be for the compiler to generate an error and force the user to use correct types. I find that implicit conversion creates more problems than it solves.
In any case, the rules in this case are pretty simple. The string is converted to an integer. But, how is a string with no digits converted? Well, the rule in MySQL is that the leading digits are converted to a number. And if there are none, the value is 0. So, this turns into:
where yeargroup = 0
You can see the results more clearly if you run:
select 'S', 'S' + 0
Note that most databases would return an error in this case (a type conversion error). But even those would accept the string if it looked like a number, so this would be allowed:
where yeargroup = '5'
What is the proper solution? Never mix types. Do not construct queries by munging constant values. Instead, queries from an application should always be using parameters.

How MySQL casts string to boolean?

During exploitation of SQL injection, I experienced weird behaviour of similar payloads:
test' AND SLEEP(5))# - not worked
1test' AND SLEEP(5))# - worked
I investigated problem and it seems that casting in (My)SQL might be unexpected:
following expressions result in 0:
1 AND '0'
1 AND '00'
1 AND 'x'
1 AND 'xx'
1 AND 'x0'
1 AND 'x1'
1 AND '0x'
and these result in 1:
1 AND '1'
1 AND '11'
1 AND '1x'
You can verify it with fiddle.
I am wondering what is the reason behind such behaviour. Is it documented or is there any reference on this?
You would appear to have a where condition such as:
where 'test' and sleep(5)
This is ridiculous, isn't it? A string where a boolean expression should be. If you were a database, the proper thing to do is to return an error of the sort that "'test' doesn't make sense here!".
But, MySQL is more generous and forgiving. Instead, it treats the string as a number and does silent conversion. Because the number has no leading digits, the conversion produces 0. Numbers are allowed in a boolean context. 0 happens to be the numeric way of saying "false".
So,
where 'test' and sleep(5)
evaluates to:
where false and sleep(5)
The "false" short-circuits the and and the second expression is not evaluated.
Similarly,
where '1test' and sleep(5)
evaluates to:
where true and sleep(5)
There is no short-circuiting and the second expression is evaluated.
We just had a similar issue and with a bit of tinkering we found out how the check works.
It appears that when evaluating a string as a boolean during a where it takes the following steps:
find first non-numeric character and take all numeric characters which are in front of it
if value of this number is higher then zero it will return true, otherwise it will return false

MYSQL boolean types

Can someone confirm if what i think about boolean is right?
There is NO boolean type within tables. Instead, mysql use numeric types.
There IS boolean type within mysql program.
SO if you make a table with BOOL column, mysql will just use TINYINT(1) and you can insert TRUE or 1 that both will have the same result.
But if you use a operator or function that only accept boolean type as parameter like the operator "IS" ( IS boolean_value ) you HAVE TO use TRUE,FALSE (or even UNKNOWN)! you CAN NOT PASS 1 as an argument!
select 1 IS 1; #syntax error
select 1 IS TRUE; #return 1
is that right?
This comes down to some definitions in the sql standard.
The sql standard defines a truth value as TRUE | FALSE | UNKNOWN.
The IS-operator is defined for the following two cases:
A boolean test: <boolean primary> [ IS [ NOT ] <truth value> ] (a boolean primary is something that can be evaluated to a boolean)
A test for the null-value: <rowvalue> IS NULL
So the correct syntax for IS requires it to be followed by either a truth value (so the words TRUE, FALSE or UNKNOWN), or NULL. E.g. select 1 IS (1=1); is not allowed either, because the result of (1=1) is a boolean, not a truth value.
This will be true for any database system that supports IS (if it does not want to violate the sql standard). So the reason you cannot use anything but one of the 4 words after IS is simply that the syntax forbids it, and is not yet an indication of how booleans are implemented. Because IS is optional in the boolean test, it's remaining main purpose is the test for the null-value, so apart from IS NULL, you usually don't ever need to use IS.
Generally, if a function requires a specific datatype (e.g. a boolean), you have to provide that datatype. But depending on the database system, there might be automatic type casting. And while some database systems do have seperate boolean datatypes, MySQL implements 1 | 0 | null as the result of a boolean expression (which is by definition a boolean):
In SQL, all logical operators evaluate to TRUE, FALSE, or NULL (UNKNOWN). In MySQL, these are implemented as 1 (TRUE), 0 (FALSE), and NULL. [...] MySQL evaluates any nonzero, non-NULL value to TRUE.
and uses this wherever booleans are used, e.g. comparison operators, and even casts it correctly if needed:
Comparison operations result in a value of 1 (TRUE), 0 (FALSE), or NULL. These operations work for both numbers and strings. Strings are automatically converted to numbers and numbers to strings as necessary.
Consequential, for MySQL the boolean datatype is a synonym for TINYINT(1).
So if you can use 1 infront of IS (where a boolean expression is required) will depend on the database system. MySQL allows you to use 1, PostgreSQL doesn't (but would allow select (1=1) IS TRUE), and MSSQL doesn't even support IS.

Select statement returns data although given value in the where clause is false

I have a table on my MySQL db named membertable. The table consists of two fields which are memberid and membername. The memberid field has the type of integer and uses auto_increment function starting from 2001. The membername table has the type of varchar.
The membertable has two records with the same order as described above. The records look like this :
memberid : 2001
membername : john smith
memberid : 2002
membername : will smith
I found something weird when I ran a SELECT statement against the memberid field. Running the following statement :
SELECT * FROM `membertable` WHERE `memberid` = '2001somecharacter'
It returned the first data.
Why did that happen? There's no record with memberid = 2001somecharacter. It looks like MySQL only search the first 4 character (2001) and when It's found related data, which is the returned data above, it denies the remaining characters.
How could this happen? And is there any way to turn off this behavior?
--
membertable uses innodb engine
This happens because mysql tries to convert "2001somecharacter" into a number which returns 2001.
Since you're comparing a number to a string, you should use
SELECT * FROM `membertable` WHERE CONVERT(`memberid`,CHAR) = '2001somecharacter';
to avoid this behavior.
OR to do it properly, is NOT put your search variable in quotes so that it has to be a number otherwise it'll blow up because of syntax error and then in front end making sure it's a number before passing in the query.
sqlfiddle
Your finding is an expexted MySQL behaviour.
MySQL converts a varchar to an integer starting from the beginning. As long as there are numeric characters wich can easily be converted, they are icluded in the conversion process. If there's a letter, the conversion stops returning the integer value of the numeric string read so far...
Here's some description of this behavior on the MySQL documentation Site. Unfortunately, it's not mentioned directly in the text, but there's an example which exactly shows this behaviour.
MySQL is very liberal in converting string values to numeric values when evaluated in numeric context.
As a demonstration, adding 0 causes the string to evaluated in a numeric context:
SELECT '2001foo' + 0 --> 2001
, '01.2-3E' + 0 --> 1.2
, 'abc567g' + 0 --> 0
When a string is evaluated in a numeric context, MySQL reads the string character by character, until it encounters a character where the string can no longer be interpreted as a numeric value, or until it reaches the end of the string.
I don't know of a way to "turn off" or disable this behavior. (There may be a setting of sql_mode that changes this behavior, but likely that change will impact other SQL statements that are working, which may stop working if that change is made.
Typically, this kind of check of the arguments is done in the application.
But if you need to do this in the SELECT statement, one option would be cast/convert the column as a character string, and then do the comparison.
But that can have some significant performance consequences. If we do a cast or convert (or any function) on a column that's in a condition in the WHERE clause, MySQL will not be able to use a range scan operation on a suitable index. We're forcing MySQL to perform the cast/convert operation on every row in the table, and compare the result to the literal.
So, that's not the best pattern.
If I needed to perform a check like that within the SQL statement, I would do something like this:
WHERE t.memberid = '2001foo' + 0
AND CAST('2001foo' + 0 AS CHAR) = '2001foo'
The first line is doing the same thing as the current query. And that can take advantage of a suitable index.
The second condition is converting the same value to a numeric, then casting that back to character, and then comparing the result to the original. With the values shown here, it will evaluate to FALSE, and the query will not return any rows.
This will also not return a row if the string value has a leading space, ' 2001'. The second condition is going to evaluate as FALSE.
When comparing an INT to a 'string', the string is converted to a number.
Converting a string to a number takes as many of the leading characters as it can and still be a number. So '2001character' is treated as the number 2001.
If you want non-numeric characters in member_id, make it VARCHAR.
If you want only numeric ids, then reject '200.1character'

Why does this work priority = ''-1 in Mysql

Can anyone tell me why this works in mysql?
update routing_policy set priority=''-1 where id = 1;
You're subtracting 1 from the empty string, evaluated as 0 for this purpose, therefore the result is -1. Take a look at the manual page about Type Conversion in Expression Evaluation for more about this.
Your value for priority is invalid:priority=''-1`. You're attempting to subtract a number from a string or your value is outside of the quotes (which shouldn't be an issue if you used an integer data type).