How can I dynamically select a list of several columns from a MSSQL table, without concatanating Strings? - sql-server

I have taken some search but ether the examples only use one parameter / columnname or they just add Strings together.
I have a table describing projets. There are unchangable columns like an id, projectnumber and such, and several 'dynamic' columns, which a user / admin can add through an interface in the application.
After that a user should see a List of all 'dynamic' Colums, and can decide to display them through checkboxes.
So what I need now, is a query as this
SELECT id, projectname, <LIST_OF_COLUM_NAMES> FROM project
I would like this to be safe from malicious Queries, like someone very clever naming a column
; DELETE TABLE projets --
and then displaying it.
I found several solutions where the querystring is just concatenated ether on the programm side or inside a stored procedure.
I found several examples for stored procedures which get one colum name and create a query statement from it.
I found this article
How to pass an array into a SQL Server stored procedure
on which I must admit I am not sure if it applies to my problem.
Is there a way to achive this without creating a security risk throug SQL-Injection?

There are several easy way to resolve this without risk of sql injection.
Write SELECT * FROM query and limit number of columns that are seen on application, this way all columns are returned and it is up to application to decide which ones to display.
Instead of passing string of columns to stored procedure, have user pass list of column indexes and based on integer value, you can have dynamic sql that generates SELECT statement only with columns that user wants back.
If you just want to display list of columns that exists in a table to the user you should select list of columns from Information Schema Views, this way you are sure which column exists in database.
In SQL-Server you can assign parameter datatype of sysname which has is how all system objects names are stored as, this could give you extra data validation.
No matter what you decide to do, you should never concatenate strings in application or stored procedures.

I tried to work with the Information Schema Views but I was not able to avoid conatenating Strings alltogether. This is what I came up with:
When the user wants to add a Column he can enter a display name, and select from a range of Datatypes. Then I create an internal unique internal column name (like DATETIME_67).
Then I create my query like this:
String querystring = "ALTER TABLE projects ADD " + internalname + " " + typestring;
Note that the String internalname and typestring are both generated inside my code, with no input from the user (so this should be safe against injection, I guess).
Then I write the internal name and the display name to a lookup table:
String querystring = "INSERT INTO lookup (tablename, displayname) " +
"VALUES (#tablename, #displayname)";
using (SQLCommand command = new SQLCommand(querystring, con)) { //con is a SQLConnection object
command.Parameters.AddWithValue("#tablename", internalname);
command.Parameters.AddWithValue("#displayname", displayname);
}
Here the actual Input from the user is inserted, but it is parameterized, so it should also be safe.
When I retrieve the columns I want to display I do also use the (hopefully) safe internal names:
List<String> selectedColumns; //the list of internal col names
String query = "SELECT id, projectnumber, projectname {0} FROM projects"; //projectnumer and name a mandatory fields
if (selectedColumns.Count > 0)
{
fieldstring = String.Join(",", selectedColumns);
fieldstring = ", " + fieldstring;
}
query = String.Format(query, fieldstring);
Please comment on this. Is is working exactly as I need it. The user can add (and remove) custom field to the datatabe and provide display names for them. He can also define, which of the present custom field are to be displayed, and he can enter data for the created fields. I am just not sure, if this save against malicious injections.

Related

Getting length of binary column in snowflake using information schema

As the title suggests, I want to determine the length that I have specified while creating the column of type BINARY in Snowflake. I tried to get this information from Information_Schema.COLUMNS view. But on inspecting the result I did not see any columns that had this information. I thought CHARACTER_OCTET_LENGTH of this view might contain this info but it does not.
I am aware that I can also use SHOW COLUMNS IN TABLE <tab_name> but for my requirement I only want to use the information_schema.
Is this information not stored in the information_schema?
I know you don't want this solution, but I will just put it here for "other people" looking for the same thing.
create table test.test.test_len(bin_10 binary(10), bin_200 binary(200) );
show columns in table test.test.test_len;
select
"column_name" as name
,parse_json("data_type"):length::number as len
from table(RESULT_SCAN());
NAME
LEN
BIN_10
10
BIN_200
200

How to query multiple JSON document schemas in Snowflake?

Could anyone tell me how to change the Stored Procedure in the article below to recursively expand all the attributes of a json file (multiple JSON document schemas)?
https://support.snowflake.net/s/article/Automating-Snowflake-Semi-Structured-JSON-Data-Handling-part-2
Craig Warman's stored procedure posted in that blog is a great idea. I asked him if it was okay to refactor his code, and he agreed. I've used the refactored version in the field, so I know the SP well as well as how it works.
It may be possible to modify the SP to work on your JSON. It will depend on whether or not Snowflake types the JSON in your variant column. The way you have it structured, it may not type everything. You can check by running this SQL and seeing if the result set includes all the columns you need:
set VARIANT_TABLE = 'WEATHER';
set VARIANT_COLUMN = 'V';
with MAIN_TABLE as
(
select * from identifier($VARIANT_TABLE) sample (1000 rows)
)
select distinct REGEXP_REPLACE(REGEXP_REPLACE(f.path, '\\[(.+)\\]'),'[^a-zA-Z0-9]','_') AS path_name, -- This generates paths with levels enclosed by double quotes (ex: "path"."to"."element"). It also strips any bracket-enclosed array element references (like "[0]")
typeof(f.value) AS attribute_type, -- This generates column datatypes.
path_name AS alias_name -- This generates column aliases based on the path
from
MAIN_TABLE,
LATERAL FLATTEN(identifier($VARIANT_COLUMN), RECURSIVE=>true) f
where TYPEOF(f.value) != 'OBJECT'
AND NOT contains(f.path, '[');
Be sure to replace the variables to your table and column names. If this picks up the type information for the columns in your JSON, then it's possible to modify this SP to do what you need. If it doesn't but there's a way to modify the query to get it to pick up the columns, that would work too.
If it doesn't pick up the columns, based on Craig's idea I decided to write type inference for non variant (such as strings from CSV log files without type information). Try the SQL above and see what results first.

Snowflake - how to display column name using function?

I did not get much help from Snowflake documentation about how I can take give column names using snowflake functions.
I have automated report which will do calculation for the given dates. here it is
select
sum(case when logdate = to_date(dateadd('day', - 10, '2019-11-14')) then eng_fees + data_fees end) AS to_date(dateadd('day', - 10, '2019-11-14'))
from myTable
where logdate = '2019-11-04'
I am getting following output for my column name below
to_date(dateadd('day', - 10, '2019-11-14'))
100
My expected output for my column name
2019-11-04
100
how can I print expected date as column name in Snowflake?
Your statement is using an AS to name your column. Snowflake will treat that as a literal, not a calculation. In order to do what you're requesting inside a function, you'll need to use a Javascript Function, I think. This will allow you to dynamically build the SQL Statement with your calculated column name predefined.
https://docs.snowflake.net/manuals/sql-reference/udf-js.html
You can't have dynamic column names without using external functionality (or TASK scheduling).
You can create a JavaScript Stored Procedure that generates a VIEW where the column names can be set by dynamic parameters / expressions.
The normal way of handling this is to use a reporting tool that can display your fixed column result set with dynamic headers or run dynamic SQL altogether.
I see 2 paths of getting close to what you want:
1) you can simply use UNION to have your headers displayed as the first row and change the actual column aliases into 1....N - so that they provide the number of column - this is going to be the fastest and the cheapest
2) you can use dynamic SQL to generate a query that will have your alias names dynamically filled and then simply run it (and you can use to example PIVOT to construct such query)

How can you create a table (or other object) that always returns the value passed to its WHERE-clause, like a mirror

There is a legacy application that uses a table to translate job names to filenames. This legacy application queries it as follows:
SELECT filename FROM aJobTable WHERE jobname = 'myJobName'
But in reality those jobnames always match the filenames (e.g. 'myJobName.job' is the jobname but also the filename) That makes this table appear unnecessary. But unfortunately, we cannot change the code of this program, and the program just needs to select it from a table.
That's actually a bit annoying. Because we do need to keep this database in sync. If a jobname is not in the table, then it cannot be used. So, as our only way out, right now we have some vbscripts to synchronize this table, adding records for each possible filename. As a result, the table just 2 columns with identical values. -- We want to get rid of this.
So, we have been dreaming about some hack that queries the data with the jobname, but just always returns the jobname again, like a copy/mirror query. Then we don't actually have to populate a table at all.
"Exploits"
The following can be configured in this legacy application. My hunch is that these may open the door for some tricks/hacks.
use of either MS Access or SQL Server (we prefer sql server)
The name of the table (e.g. aJobTable)
The name of the filename column (e.g. filename)
The name of the jobname column (e.g. jobname)
Here is what I came up with:
If I create a table-valued function mirror(a) then I get pretty close to what I want. Then I could use it like
SELECT filename FROM mirror('MyJobName.job')
But that's just not good enough, it would be if I could force it to be like
SELECT filename FROM mirror WHERE param1 = 'MyJobName.job'
Unfortunately, I don't think it's possible to call functions like that.
So, I was wondering if perhaps somebody else knows how to get it working.
So my question is: "How can you create a table (or other object) that always returns the value passed to its WHERE-clause, like a mirror."
It's kinda hard to answer not knowing the code that the application use, but if we assume it only takes strings and concatenate them without any tests whatsoever, I would assume code like this: (translated to c#)
var sql = "SELECT "+ field +" FROM "+ table +" WHERE "+ conditionColumn +" = '"+ searchValue +"'";
As this is an open door for SQL injection, and given the fact that SQL Server allows you two ways of creating an alias - value as alias and alias = value,
you can take advantage of that and try to generate an SQL statement like this:
SELECT field /* FROM table WHERE conditionColumn */ = 'searchValue'
So field should be "field /* ",
and conditionColumn should be "conditionColumn */"
table name doesn't matter, you could leave an empty string for it.

Codename One: AutoComplete textfield connection with SQLite

I would like to connect an autocomplete text field to an SQLite database. The user should be able to type in a few letters and then select the item they would like to add from possible suggestions. Once the user adds the item (by pressing a button), an SQL query should retrieve other values from the selected item row.
Example of database table row.
To summarise, I would like the following:
An autocomplete component to provide suggested items (ItemName from database) after the user types a few letters
Perform an SQL query to retrieve values (Salt and Sugar from database) and keep a running total of salt and sugar. Theses values should then be added to a table containing 2 rows with 2 columns, as follows.
Salt | [value from database + total salt]
Sugar | [value from database + total sugar]
I would therefore appreciate therefore any advice and guidance on how these could be implemented.
You need to use a select query on ItemName specifically:
select `ItemName` from tablename
Then use that data for your auto complete code.
When the action listener for the auto complete fires just issues the query
"select * from tablename where ItemName='" + mySelection + "'"
Then use the column values in the returned row. You also need to deal with a case of nothing being returned if the user typed in something that isn't available in the list and pressed "Done".

Resources