-3

Found the issue:

  • SqlKata compiler was transforming the column names into string literals, so that was returned when a matching column was not located.
  • Updating the queries to use brackets instead of quotes resolved the issue.
  • Created github issue here regarding the issue: https://github.com/sqlkata/querybuilder/issues/655

Initial post contents retained below.


I was doing some unit testing against a Sqlite database, ensuring that my methods for creation and reading all work fine (They do). But One of the tests failed, and I am absolutely confused as to why.

The Sqlite db consists of a single table, defined below: TableName: Students Columns: ID (Primary Key), FirstName (string), LastName (string)

The following query works properly, returning the 'FirstName' value within the db:

"SELECT \"FirstName\" FROM \"Students\" WHERE \"ID\" = @p0"

The following query I would expect would cause an exception, since the column name does not exist:

"SELECT \"UnknownCol\" FROM \"Students\" WHERE \"ID\" = @p0"

Instead, I receive the value 'UnknownCol' as a string result.

For reference, I’m using the same method (which processes a DbCommand object) to perform the same thing at against an Excel file via OledbCommand. That function produces an exception (not a helpful one, but atleast it error our). So I know the underlying method works.

Why would sqlite return the name of a column that doesn't exist in that query?

Additional Info Edit:

Using an OledbConnection to read from an Excel sheet using the same method results in the following exception when I request an invalid column within the query (which while it doesn't tell you its a bad query due to invalid column name, atleast it errors out):

Exception Message: No value given for one or more required parameters.

Full code chain:

//db object has a method that returns a SqliteConnection, and has a 'Compiler' property that returns the SqlKata.Compiler object for SqlLite

var qry = new SqlKata.Query("Students").Select("UnknownCol").Where("ID",1);
return GetValue(db.GetConnection(), qry, db.Compiler);

//Results in the following sql: 
"SELECT \"UnknownCol\" FROM \"Students\" WHERE \"ID\" = 1"


---
public static object GetValue(DbConnection connection, Query query, SqlKata.Compilers.Compiler compiler)
{
    using (var cmd = connection.CreateCommand(query, compiler))
    {
        connection.Open();
        try
        {
            return cmd.ExecuteScalar();    
        }
        finally
        {
            connection.Close();
        }
    }
}

public static DbCommand CreateCommand(this DbConnection connection, SqlKata.Query query, SqlKata.Compilers.Compiler compiler)
{
    if (connection is null) throw new ArgumentNullException(nameof(connection));
    if (compiler is null) throw new ArgumentNullException(nameof(compiler));
    var result = compiler.Compile(query ?? throw new ArgumentNullException(nameof(query)));
    var cmd = connection.CreateCommand();
    cmd.CommandText = result.Sql;
    foreach (var p in result.NamedBindings)
    {
        _ = cmd.AddParameter(p.Key, p.Value);
    }
    return cmd;
}

public static DbParameter AddParameter(this DbCommand command, string name, object value)
{
    var par = command.CreateParameter();
    par.ParameterName = name;
    par.Value = value;
    command.Parameters.Add(par);
    return par;
}

RFBomb
  • 51
  • 6
  • Post the code you use to construct `query` and call `GetValue()` – forpas Jan 07 '23 at 13:42
  • these character `[]` are not part of naming column in sql, what's the exact query you're running on the database ? but you can see my answer anyway as it's probably what the query is. – davidriod Jan 07 '23 at 13:57
  • @forpas - Added additional methods – RFBomb Jan 07 '23 at 14:04
  • @davidriod - I was used to other sql statements that use brackets, so I just typed that while writing this. My bad. Upon inspection of the code, it does use \" to wrap the identifiers. I have updated the post accordingly. Interestingly, when I DO run the code using brackets, I get the exception for column missing! The SqlKata Compiler itself is whats generating the sql code though, which works as long as its a valid query. – RFBomb Jan 07 '23 at 14:06
  • "MissingColumnTest" is a string literal and not a column name when there is no column with that name. I wonder why in your original question you presented the column as `[MissingColumnTest]` – forpas Jan 07 '23 at 14:06
  • @davidriod square brackets are valid in SQLite. – forpas Jan 07 '23 at 14:07
  • @forpas - That was my bad. I was originally typing this up on a phone, so paraphrased instead of copy-pasted the code directly. MissingColumnTest was the actual code within my unit test. – RFBomb Jan 07 '23 at 14:08
  • @forpas indeed I stand corrected, I've never used that. Thanks for your insight. – davidriod Jan 07 '23 at 14:10

1 Answers1

2

It's legal to select a string litteral in SQL. This is a valid SQL query which returns the mentioned string:

SELECT 'UnknownCol';

It will return a single row containing this string litteral. The following query is similar

SELECT 'UnknownCol' FROM students;

For each row in your table, it will return a row with this string litteral. Here is an example on a test table with a few rows in a test database:

sqlite> select 'a string litteral' from test;
a string litteral
a string litteral
a string litteral
a string litteral
a string litteral
sqlite> select count(1) from test;
5
sqlite>

If you want to query a specific column name instead of a string litteral you have to remove the '' characters around the column name. Then this is the result with an undefined column:

sqlite> select unknowncol from test;
Parse error: no such column: unknowncol
  select unknowncol from test;
         ^--- error here
sqlite>

or for a defined column:

sqlite> select id from test;
1
2
3
4
6
sqlite>
davidriod
  • 937
  • 5
  • 14
  • So let me get this straight, you can 'query a string literal' from a table, and simply get the literal back? I can't fathom what purpose that would serve. Unless it can be used to concatenate two columns together. Otherwise, that seems an odd interaction to me. But anyway, it sounds like the issue at hand is that SqlKata is wrapping the column name, transforming it into a string literal? – RFBomb Jan 07 '23 at 14:12
  • For reference, if I wrap the column name with brackets, I DO get the exception to occur, but SqlKata only outputs with quote-wrapping – RFBomb Jan 07 '23 at 14:14
  • @RFBomb no SqlKata is not transforming it to a column name. When SQLite's parser sees `"`FirstName`"` searches for a column named `FirstName`. If this column is not found then it treats it as a string literal. – forpas Jan 07 '23 at 14:29
  • @forpas - I'm sending the string into the SqlKata.Query into the 'columns' parameter. I understand the interaction now, but the problem itself was due to SqlKata not properly wrapping it for this scenario, when brackets work fine (and most other compilers are wrapping with brackets). Due SqlKata effectively turning it into a string literal, the issue occurs. – RFBomb Jan 07 '23 at 14:37
  • Marking this as the answer since it was in fact the issue at hand, I just wasn't aware that this type of query was allowed (and still don't see why its needed). But it led me to the root cause. @forpas - thanks for the help, as it led me to furthering my diving into the object values where I hadn't thought to, which supported this 'string literal' as the cause – RFBomb Jan 07 '23 at 14:43