Coldfusion query caching with arguments [duplicate] - sql

When you use the cachedwithin attribute in a cfquery how does it store the query in memory. Does it store it by only the name you assign to the query? For example, if on my index page I cache a query for an hour and name it getPeople will a query with the same name on a different page (or the same page for that matter) use the cached results or does it use some better logic to decide if it is the same query?
Also, if there is a variable in your query does the cache take into account the value of the variable?

It's not only the name -- it's the exact query you're running.
<cfquery name="getPeople" cachedwithin=".5" ...>
select name from employee order by name
</cfquery>
If you invoke this same query anywhere else in your app, you'll get the cached version if it's within half a day of the first query. But these will hit the database for fresh data:
<!--- Different name, same SQL: A new cached query --->
<cfquery name="getEmployees" cachedwithin=".5" ...>
select name from employee order by name
</cfquery>
<!--- Different SQL, same name: Redefining the cached query --->
<!--- Note: As pointed out in comments, it's not really overwriting the old query
of the same name, but making a new one in the cache. The first one by the
same name is still in the cache, waiting for eviction. --->
<cfquery name="getPeople" cachedwithin=".5" ...>
select name from employee order by name desc
</cfquery>
And yes, it does take a variable into account. If you use cfqueryparam -- which you should be doing -- your database will cache the query plan, but even using cachedwithin, each query with a changed parameter will be treated as different from a query caching perspective. Note that this means if you use cachedwithin on a query that runs many times with different parameters, you'll be flooding your query cache with queries that have low cache hit rates.

From http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7fae.html
To use cached data, current query
must use same SQL statement, data
source, query name, user name,
password.
So those are the 'keys' that "decide if it is the same query"
variable? yes, as long as you use <cfqueryparam>

Related

ColdFusion Sanatize SQL

I'm trying to loop over tableList and run a query for each table getting the count from each. Not all of the code is included but the problem is the cfqueryparam. When I run this code right now the error says "INVALID TABLE NAME". Here is what I am trying right now:
<cfloop list="#tableList#" index="t">
<cfquery name="getcount" datasource="erisnetselect">
SELECT COUNT(*) FROM <cfqueryparam value='AUDITOR.#t#' sqltype="VARCHAR">
</cfquery>
The problem is specifically this line:
SELECT COUNT(*) FROM <cfqueryparam value='AUDITOR.#t#' sqltype="VARCHAR">
I have also tried:
SELECT COUNT(*) FROM AUDITOR.<cfqueryparam value='#t#' sqltype="VARCHAR">
But I get the same error.
I think there might be a way to sanitize these table names before they hit the query but I'm not sure how to do it. If you need all of the code I can provide more but this is a huge page.
cfqueryparam is a value placeholder for a prepared statement. You cannot use value placeholders for table or column names because a prepared statement requires the query to be complete and valid before any values are put in. One of the design goals of prepared statements is to prevent malicious injection by separating query and values. The separation is achieved by sending the query without actual values first (value placeholders are usually indicated with a question mark ?), have the SQL server parse and understand it (query interpreter) and then wait for data to place into the prepared value slots. This also comes with a performance benefit, because the SQL server can reuse already interpreted queries while sending a plain string statement with query and values would always require parsing it again.
To solve your problem, you will have to sanitize the table names either by using the appropriate command builder/quoter (depends on the SQL vendor, check your JDBC driver) or validate the name manually.
If you have to go with the manual way, you should be conservative and only allow foolproof characters, such as alphabetic letters, digits, underscores and hyphens. Consider this:
<cfloop list="#tableList#" index="t">
<!--- make sure the table name only consists of alphabetic letters, digits, underscores and hyphens --->
<cfif not reFind("^[a-zA-Z0-9_-]+$", t)>
<cfthrow message='The specified table name, which is "#t#", contains illegal characters.'>
</cfif>
<cfquery name="getcount" datasource="erisnetselect">
SELECT COUNT(*) FROM AUDITOR.#t#
</cfquery>
...

Can you get column names from a Select statement in the big query SDK without running it

Given a SELECT statement in Big Query and the Java SDK, what are my options to get the actual column names without fetching the data? I know I can execute the statement and then get the Schema via the TableResult. But is there a way to get the names without fetching data? We have a tool where we run arbitrary queries which are not known upfront and in my code I want to access the result columns by name.
Update: someone flagged this as duplicate of a 7 year old entry. I am however looking for a way to use the Java SDK alone to get the column names, not to do some magic with the query itself or query some metatable.
There are few options but the easiest is to add limit 0 to your query so for example:
SELECT * FROM projectId.datasetId.tableId limit 0

SQL, how to pick portion of list of items via SELECT, WHERE clauses?

I'm passing three parameter to URL: &p1=eventID, &p2=firstItem, &p3=numberOfItems. first parameter is a column of table. second parameter is the first item that I'm looking for. Third parameter says pick how many items after firstItem.
for example in first query user send &p1=1, &p2=0, &p3=20. Therefore, I need first 20 items of list.
Next time if user sends &p1=1, &p2=21, &p3=20, then I should pass second 20 items (from item 21 to item 41).
PHP file is able to get parameters. currently, I'm using following string to query into database:
public function getPlaceList($eventId, $firstItem, $numberOfItems) {
$records = array();
$query = "select * from {$this->TB_ACT_PLACES} where eventid={$eventId}";
...
}
Result is a long list of items. If I add LIMIT 20 at the end of string, then since I'm not using Token then result always is same.
how to change the query in a way that meets my requirement?
any suggestion would be appreciated. Thanks
=> update:
I can get the whole list of items and then select from my first item to last item via for(;;) loop. But I want to know is it possible to do similar thing via sql? I guess this way is more efficient way.
I would construct the final query to be like this:
SELECT <column list> /* never use "select *" in production! */
FROM Table
WHERE p1ColumnName >= p2FirstItem
ORDER BY p1ColumnName
LIMIT p3NumberOfItems
The ORDER BY is important; according to my reading of the documentation, PostGreSql won't guarantee which rows you get without it. I know Sql Server works much the same way.
Beyond this, I'm not sure how to build this query safely. You'll need to be very careful that your method for constructing that sql statement does not leave you vulnerable to sql injection attacks. At first glance, it looks like I could very easily put a malicious value into your column name url parameter.
If you are using mysql, then use the LIMIT keyword.
SELECT *
FROM Table
LIMIT $firstItem, $numberOfItems
See the documentation here (search for LIMIT in the page).
I found my answer here: stackoverflow.com/a/8242764/513413
For other's reference, I changed my query based on what Joel and above link said:
$query = "select places.title, places.summary, places.description, places.year, places.date from places where places.eventid = $eventId order by places.date limit $numberOfItems offset $firstItem";

SQL Injection clarification

There is a query like:
select * from tablename where username='value1' and password='value2';
If I set to the fields the following:
username ='admin' and password ='admin';
Then I sign in into the website as administrator.
Now, If I wanted to SQL inject my query, I would enter to the username field the value 'or 1=1, after which the query would be executed like:
select * from tablename where username ='' or 1=1
Assuming everything after this the query is executed successfully.
My question is based on above example, what user we will be logged in as?
As:
1. Admin
2. Or first row in table?
3. Or any other user and how?
That is just a SQL query, it does not login or do any other application functionality. What is done with the data retrieved is entirely dependent on the specific application.
The code may happily consume the first row in the resulting recordset and assume that is the user to be logged in. It may also throw an exception, e.g., if the query is being done with LINQ and .SingleOrDefault() is used. Without seeing the application code, there is no way to know.
All rows in the tablename table will be returned to whatever is running this query. The order in which these rows are returned isn't well defined (and tables don't have an order, so your guess of "first row" is wrong for a number of reasons)
We'd then need to see the consuming code to know what happens - it might take the first row it's given, it might take the last row it's given (different runs of this query could have different first and last rows, because as I said, the order isn't well defined). It may attempt to (in some manner) merge all of the resulting rows together.
You shouldn't try to reason about what happens when your code is subject to SQL injection, you should just apply adequate defenses (e.g. parameterized queries) so you don't have to think about it again.
For example, lets say, for the sake of argument, that this query always returned the rows in some particular order (so long as the moon is full), such that the lowest UserID (or similar) is the first row, and that the consuming code uses the first returned row and ignores other rows. So you decide to "cunningly" create a dummy user with UserID 0 which can't do anything and warns you of an attack.
Well, guess what - all the attacker has to do is inject an ORDER BY CASE WHEN UserName='Admin' THEN 0 ELSE 1 END into the query - and bingo, the first row returned is now guaranteed to be the Admin user.

why would you use WHERE 1=0 statement in SQL?

I saw a query run in a log file on an application. and it contained a query like:
SELECT ID FROM CUST_ATTR49 WHERE 1=0
what is the use of such a query that is bound to return nothing?
A query like this can be used to ping the database. The clause:
WHERE 1=0
Ensures that non data is sent back, so no CPU charge, no Network traffic or other resource consumption.
A query like that can test for:
server availability
CUST_ATTR49 table existence
ID column existence
Keeping a connection alive
Cause a trigger to fire without changing any rows (with the where clause, but not in a select query)
manage many OR conditions in dynamic queries (e.g WHERE 1=0 OR <condition>)
This may be also used to extract the table schema from a table without extracting any data inside that table. As Andrea Colleoni said those will be the other benefits of using this.
A usecase I can think of: you have a filter form where you don't want to have any search results. If you specify some filter, they get added to the where clause.
Or it's usually used if you have to create a sql query by hand. E.g. you don't want to check whether the where clause is empty or not..and you can just add stuff like this:
where := "WHERE 0=1"
if X then where := where + " OR ... "
if Y then where := where + " OR ... "
(if you connect the clauses with OR you need 0=1, if you have AND you have 1=1)
As an answer - but also as further clarification to what #AndreaColleoni already mentioned:
manage many OR conditions in dynamic queries (e.g WHERE 1=0 OR <condition>)
Purpose as an on/off switch
I am using this as a switch (on/off) statement for portions of my Query.
If I were to use
WHERE 1=1
AND (0=? OR first_name = ?)
AND (0=? OR last_name = ?)
Then I can use the first bind variable (?) to turn on or off the first_name search criterium. , and the third bind variable (?) to turn on or off the last_name criterium.
I have also added a literal 1=1 just for esthetics so the text of the query aligns nicely.
For just those two criteria, it does not appear that helpful, as one might thing it is just easier to do the same by dynamically building your WHERE condition by either putting only first_name or last_name, or both, or none. So your code will have to dynamically build 4 versions of the same query. Imagine what would happen if you have 10 different criteria to consider, then how many combinations of the same query will you have to manage then?
Compile Time Optimization
I also might add that adding in the 0=? as a bind variable switch will not work very well if all your criteria are indexed. The run time optimizer that will select appropriate indexes and execution plans, might just not see the cost benefit of using the index in those slightly more complex predicates. Hence I usally advice, to inject the 0 / 1 explicitly into your query (string concatenating it in in your sql, or doing some search/replace). Doing so will give the compiler the chance to optimize out redundant statements, and give the Runtime Executer a much simpler query to look at.
(0=1 OR cond = ?) --> (cond = ?)
(0=0 OR cond = ?) --> Always True (ignore predicate)
In the second statement above the compiler knows that it never has to even consider the second part of the condition (cond = ?), and it will simply remove the entire predicate. If it were a bind variable, the compiler could never have accomplished this.
Because you are simply, and forcedly, injecting a 0/1, there is zero chance of SQL injections.
In my SQL's, as one approach, I typically place my sql injection points as ${literal_name}, and I then simply search/replace using a regex any ${...} occurrence with the appropriate literal, before I even let the compiler have a stab at it. This basically leads to a query stored as follows:
WHERE 1=1
AND (0=${cond1_enabled} OR cond1 = ?)
AND (0=${cond2_enabled} OR cond2 = ?)
Looks good, easily understood, the compiler handles it well, and the Runtime Cost Based Optimizer understands it better and will have a higher likelihood of selecting the right index.
I take special care in what I inject. Prime way for passing variables is and remains bind variables for all the obvious reasons.
This is very good in metadata fetching and makes thing generic.
Many DBs have optimizer so they will not actually execute it but its still a valid SQL statement and should execute on all DBs.
This will not fetch any result, but you know column names are valid, data types etc. If it does not execute you know something is wrong with DB(not up etc.)
So many generic programs execute this dummy statement for testing and fetching metadata.
Some systems use scripts and can dynamically set selected records to be hidden from a full list; so a false condition needs to be passed to the SQL. For example, three records out of 500 may be marked as Privacy for medical reasons and should not be visible to everyone. A dynamic query will control the 500 records are visible to those in HR, while 497 are visible to managers. A value would be passed to the SQL clause that is conditionally set, i.e. ' WHERE 1=1 ' or ' WHERE 1=0 ', depending who is logged into the system.
quoted from Greg
If the list of conditions is not known at compile time and is instead
built at run time, you don't have to worry about whether you have one
or more than one condition. You can generate them all like:
and
and concatenate them all together. With the 1=1 at the start, the
initial and has something to associate with.
I've never seen this used for any kind of injection protection, as you
say it doesn't seem like it would help much. I have seen it used as an
implementation convenience. The SQL query engine will end up ignoring
the 1=1 so it should have no performance impact.
Why would someone use WHERE 1=1 AND <conditions> in a SQL clause?
If the user intends to only append records, then the fastest method is open the recordset without returning any existing records.
It can be useful when only table metadata is desired in an application. For example, if you are writing a JDBC application and want to get the column display size of columns in the table.
Pasting a code snippet here
String query = "SELECT * from <Table_name> where 1=0";
PreparedStatement stmt = connection.prepareStatement(query);
ResultSet rs = stmt.executeQuery();
ResultSetMetaData rsMD = rs.getMetaData();
int columnCount = rsMD.getColumnCount();
for(int i=0;i<columnCount;i++) {
System.out.println("Column display size is: " + rsMD.getColumnDisplaySize(i+1));
}
Here having a query like "select * from table" can cause performance issues if you are dealing with huge data because it will try to fetch all the records from the table. Instead if you provide a query like "select * from table where 1=0" then it will fetch only table metadata and not the records so it will be efficient.
Per user milso in another thread, another purpose for "WHERE 1=0":
CREATE TABLE New_table_name as select * FROM Old_table_name WHERE 1 =
2;
this will create a new table with same schema as old table. (Very
handy if you want to load some data for compares)
An example of using a where condition of 1=0 is found in the Northwind 2007 database. On the main page the New Customer Order and New Purchase Order command buttons use embedded macros with the Where Condition set to 1=0. This opens the form with a filter that forces the sub-form to display only records related to the parent form. This can be verified by opening either of those forms from the tree without using the macro. When opened this way all records are displayed by the sub-form.
In ActiveRecord ORM, part of RubyOnRails:
Post.where(category_id: []).to_sql
# => SELECT * FROM posts WHERE 1=0
This is presumably because the following is invalid (at least in Postgres):
select id FROM bookings WHERE office_id IN ()
It seems like, that someone is trying to hack your database. It looks like someone tried mysql injection. You can read more about it here: Mysql Injection