System.IndexOutOfRangeException on SqlDataReader.get_Item() only when using alias - c#

I have a sql query that I am creating and running through C# code using SqlDataReader. The query is quite simple, it amounts to:
SELECT colName1 AS altColName1, colName2 AS altColName2 FROM table.
When I run the query in SQL Server Management Studio it works and gives the expected results.
Additionally, when I run the simpler query:
SELECT colName1, colName2 FROM table
using the SqlDataReader it works fine, except obviously I don't get the aliases.
The problem is, when using SqlDataReader and giving it the first query, I get:
System.IndexOutOfRangeException -- colName1
I'm perplexed since obviously that index works fine without the alias attached. Am I doing something wrong? Or is there some workaround I can use to get the query to work with the alias?
edit: I got it to work correctly by changing the query to:
SELECT DISTINCT colName1 AS altColName1, colName2 AS altColName2 FROM table
though I don't understand exactly why this works and the original did not.

You obtain System.IndexOutOfRangeException for colName1 because, using SELECT with aliases, the correct name to use is altColName1.
So you have to stick to column name or change the code in your SqlDataReader.get_Item().
SqlDataReader.Item property gets the value of the specified column in its native format given the column name. So in your code you could find a call like yourSqlDataReader("colName1") that don't work if you rename your column as altColName1.

Related

How to use FETCH in OleDb query?

I have xlsx table like this:
Name SubDatasetCount Parameter1 Parameter2 ParameterX .......
Dataset1
SubDataset1
SubDataset2
SubDatasetX
Dataset2
SubDataset1
SubDataset2
SubDatasetX
.
.
.
My goal is to load any Dataset Parameters and all its SubDatasets.
Xlsx format and reading method is given. At this moment I read Data1-SubDataCount and then I try to run following SQL query for OleDbReader:
SELECT *
FROM ["SheetName"$]
WHERE Name LIKE '%DatasetName%'
FETCH NEXT [SubDatasetCount] ROWS ONLY
It cause OleDbException: 'IErrorInfo.GetDescription failed with E_FAIL(0x80004005).' . Prior addition of FETCH query worked fine. I have no SQL knowledge, I copied it from here: How to select next rows from database in C#?
In linked answer there is statement that ORDER BYis a MUST, but I can not do that obviously.
And even when I tested following query, error is same:
SELECT *
FROM ["SheetName"$]
WHERE Name LIKE '%DatasetName%'
ORDER BY Name
FETCH NEXT 10 ROWS ONLY
It works when I remove FETCH and leave ORDER BY. Quick study of that specific error yields always same result - reserved keyword is used in the query. But I don't see anything like that in FETCH part of query.
How do I make FETCH work?
In case FETCH is fixed somehow, how to solve ORDER BY requirement? ORDER BY(SELECT NULL) cause exception.

ExecuteSqlInterpolated/ExecuteSqlRaw parameters pass to database incorrectly in asp.net core

I am attempting to use ExecuteSqlInterpolated to update my database. However, it seems that there is a problem with my SQL parameters. Running the following code correctly updates intField1 and intField2, however stringField becomes the string "#p0".
_context.Database.ExecuteSqlInterpolated($"UPDATE table SET stringField='{someString}', intField1={someInt}, intField2={someOtherInt} WHERE id='{id}'");
I have already verified that my variables contain the desired values when the string is passed to the method. I understand that #p0 is what SQL uses to represent the first parameter in the query, but why isn't it being replaced by the string I gave it? I have also tried using ExecuteSqlRaw but ran into the same issue. My knowledge of SQL is limited at best, I know just enough to get by in web dev, so I'm guessing I'm committing some simple error in crafting the query here, but obviously I'm not sure.
I know it's late but just don't use quotation mark with your parameters, specially where you use int data-type
(delete single quotes)
_context.Database.ExecuteSqlInterpolated($"UPDATE table SET stringField={someString}, intField1={someInt}, intField2={someOtherInt} WHERE id={id}");

The data reader is incompatible with the specified class

so there are a few other similar type posts about, but none matching the simple task I am attempting.
just running a stored proc through EF6 code first in the following manner
var results = context.DataBase.SqlQuery<MyClass>("exec spGetStuff #param1, #param2", new SqlParameter[] {new SqlParameter("param1",value), new SqlParameter("param2", value2)});
I have used this method on many occasions with no issue.
the class I am mapping the results to is pretty nasty with many properties, but all that need it are marked with the [Column("dbfieldname")] attribute.
all the stored proc is doing is returning some results by using a
SELECT * FROM(
SELECT
ROW_NUMBER() OVER ( PARTITION BY X,Y,Z ORDER BY A) [RowNumber]
,*
FROM
MyTableNAme
WHERE
...) S
WHERE s.RowNumber = 1
not inserting, updating or anything fantastical like that.
The data reader is incompatible with the specified 'MyClass'. A member of the type, 'PropertyNameName', does not have a corresponding column in the data reader with the same name.
if I do change the class properties to the db column names it seems to work fine:I can change the first few properties and it will then fail on other ones in the class... however I do not really want to do that if I can possibly avoid it as most of the columns in the DB are named very badly indeed, so I guess my question is why is it ignoring the [Column()] attributes that have never failed me before.
or is the issue the row_number, which I have tried adding to the class an/or removing from the query resultsset.
We're seeing this issue too since upgrading and refactoring for EF6 from 5. Stored procedure returns and we have a Complex Type defined in our edmx. It seems that everything matches up but we get the same type of error when calling like this
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<GetColumnValueSet_Result>("GetColumnValueSet", param1, param2, param3);
So after trying a few things this is what I found. I opened my edmx and went to the Model Browser within Visual Studio. Under Function Imports I found my sproc. Right clicked and chose Function Import Mapping. It turned out that even though the complex type was correct and it appeared everything should have matched up the Function Import Mapping was thinking the sproc was returning a column called CodeValue instead of Value (which is what it was actually importing).
So for some reason when the sproc columns were gotten it go a wrong name for the mapping.

c# System.Data.SQLite parameters error

I am using SQlite database on C# and have an error issue with parameters.
using System.Data.SQLite;
Here is a main code part:
this.dbUpdateCommand = new SQLiteCommand();
dbUpdateCommand.Parameters.AddWithValue("#paramNewValue", (string)this.valueNew);
dbUpdateCommand.Parameters.AddWithValue("#paramPredValue", (string)this.valuePred);
dbUpdateCommand.Parameters.AddWithValue("#paramTableName", (string) this.tableName);
dbUpdateCommand.Parameters.AddWithValue("#paramColumnName", (string)this.columnInDB);
dbUpdateCommand.Parameters.AddWithValue("#paramKeyField", (string)this.keyFieldInDB);
dbUpdateCommand.Parameters.AddWithValue("#paramKeyValue", (string)this.keyValueInDB);
dbUpdateCommand.CommandText = "UPDATE #paramTableName SET #paramColumnName=#paramNewValue WHERE #paramKeyField=#paramKeyValue;";
dbUpdateCommand.ExecuteNonQuery();
And it throws me exception "SQLite error near "#paramTableName": syntax error"
I tried to make pure SQL statement without params but with strings concatenation and it works with the same variables (this.tableName is valid db tablename)
So it seems something wrong with my parameters. Does anybody knows, what?
You can't use parameters to reference objects (tables & columns). You would need to drop the actual table and column names into your query. Be careful of SQL injection while doing so.

Execute query only if it is select statement. How?

string sqlQuery = "unknown";
I need to write a function which receives a sql query as parameter e.g. sqlQuery. I would like to execute it only if it is select statement and return data. In other case, if parameter sqlQuery contains delete, update or truncate, the function should return null.
I wonder if there is way to achieve this without parsing contents of parameter sqlQuery.
I would like to do this using c sharp for oracle queries.
Any tips. Thanks.
Update:
This should work for all kinds of users with all privileges.
Run the query in the context of a user who only has select privileges. Any other type of query will error out.
SET TRANSACTION READ ONLY, then execute the string. If it attempts to modify data, it will generate an ORA-01456 error. You can trap this and return whatever you want.
If you really have to work with a constructed string that will operate on the database, you should use the DBMS_ASSERT database package to make sure you have a pure query that's not subject to SQL injection. There's a nice paper on the Oracle site about that here.
The basics are:
only give the minimum privileges necessary, for example only giving the user "select" as described in an earlier reply. And then only on the minimum necessary set of tables. Views are really helpful here in limiting access.
Use bind variables where that's possible.
If you can't use bind variables then check the purity of your statement using DBMS_ASSERT
You can probably search the string for keywords like "update", "delete", "truncate" and all the other ways you can do ddl or dml on the table, but it is very error-prone. You have to eliminate strings in the query which might have these keywords and there are a lot of keywords that you have to take into account.
If your requirement is to return null, Why not give just the select privilege on the necessary objects and return null if you encounter the Insufficient Privileges error?
http://download.oracle.com/docs/cd/E11882_01/server.112/e17069/strms_trapply.htm#STRMS1065
I would not allow the client to specify a SQL select string. Too many possible attack vectors.
Have you considered using Linq? The caller could pass a Func<T, bool> that could be passed to a Where clause. Since Linq will generate the select statement for you, there's no possibility of a non-select statement occuring.
Bear in mind a SELECT column FROM table FOR UPDATE will still take an exclusive lock on every row on that table. And it only needs SELECT privileges (none of INSERT, UPDATE or DELETE are required).
You can use ADO.NET SqlCommand http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.aspx. It has methods ExecuteReader for a select type query and ExecuteNonQuery for other sql expression, you jest set the CommandText string attribute. If I'm right it throws exception if the query is not a select in ExecuteReader but you must check it.
string sqlQuery = "("+evil_sql+")";
Only a subquery can start with a parentheses. This will stop DML, DDL, and the FOR UPDATE issue that Gary mentioned. You still have to execute everything, just catch all the errors. I've done this on a public-facing website without any issues.
Even if your user is not directly granted anything you'll need to check for unnecessary PUBLIC grants. And of course keep your system patched. There have been exploits in functions that can be called in a SELECT.

Categories