>

PostHeaderIcon QUERY and the Database

Not needing a SQL database for every site or every table means you can use Interchange in more hosting environments, but that''s has usually come at the cost of being able to use SQL as your query language. Fortunately Interchange comes with a built-in SQL interpreter, which means you can use a single query language even if your tables are stored in a "flat file" instead of something like MySQL or Oracle. The QUERY tag is the main interface for executing arbitrary SQL on any table, regardless of the back-end.

QUERY synopsis

[query
	list="1"
	sql="SELECT * FROM products WHERE prod_group = 'Toys'"]

	<li>[sql-param description] - [price [sql-code]]</li>

[/query]

Step 1

QUERY is a container tag surrounding code that's repeated for each row returned by the query, so it always has a closing

tag.

Step 2

Passing list="1" tells Interchange that you're expecting a "list"--or multiple rows, in other words. If you don''t pass this, the code surrounded by the QUERY tags won''t be executed. You need to pass this even if you''re only expecting one row in the results. If you remember that "SELECT is a LIST" it won''t be a problem. But the QUERY tag is versatile enough that you can also run UPDATE and INSERT queries, and for these you can omit the list="1" parameter. You'll still need a closing QUERY tag, though.

Step 3

The actual query is passed in the sql="SELECT..." parameter. From within here you can also use other Interchange tags, such as SCRATCH. Remember to quote anything, where necessary, like this:
[query
	list="1"
	sql="SELECT * FROM products WHERE prod_group = '[scratch prod_group]'"]

	... your code here ...

[/query]
Security warning: It's tempting to pass user input in some form when creating queries. Writing prod_group='[CGI prod_group]' is a quick and easy way to start a search results page, but it can be exploited by a hacker, who could pass something like this:
	foo'; delete from products where sku != '
In this example, the ending quote and semicolon after foo closes the WHERE clause of the first query and then closes the query. The following query can then be executed, deleting all the products in your store. The code reading where sku != ' just makes sure there's no syntax error that'd otherwise stop his malicious query from running. To avoid accidents like this, you can screen incoming user data for quote marks and save the result in a scratch variable, like this:
[tmp prod_group][calc] 
	my $group = $CGI->{prod_group};
	$group =~ s/'/''/g;
	return $group;
[/calc][/tmp]
The perl code here is substituting each single quote for a pair of single quotes (that's not a double quote there, it's two singles), which is how most SQL databases encode the quote character for use within strings passed to queries. With that in place, the hacker can't get a malicious query to run, because he can't break out of the first. In the worst case, the query would simply fail rather than delete all of your products. You should always screen form-submitted data even if you're passing it through hidden variables, or SELECT lists that constrain the input. None of these methods stop a hacker from contriving a GET or POST form submission with whatever he likes.

Step 4

The code to be run for each row of results is interpolated for SQL tags. The first useful tag is SQL-PARAM, which lets you pull any column from the results, even computed, virtual or renamed columns. For example:
[query
	list="1"
	sql="SELECT sku,description,
		date_format(entered,'%Y-%m-%d') as added,
		price + 10 as compare 
		FROM products"]

	<li>[sql-param description] added [sql-param added] 
		- [price [sql-code]] (compare to $[sql-param compare])</li>

[/query]

Advanced

ON-MATCH and NO-MATCH

Like with Interchange's tags for summarizing search results, QUERY also understands the ON-MATCH and NO-MATCH tags to display something once when it finds rows, or doesn't.
[query
	list="1"
	sql="SELECT * FROM products WHERE prod_group = '[scratch prod_group]'"]

	[on-match]
		<p>We found the following products for [scratch prod_group].</p>
		<ul>
	[/on-match]

	[list]
		<li>[sql-param description] - [price [sql-code]]</li>
	[/list]

	[on-match]
		</ul>
	[/on-match]

	[no-match]
		<p>Sorry, no matches for [scratch prod_group].</p>
	[/no-match]

[/query]
When you use the ON-MATCH or NO-MATCH tags, you imply the use of LIST as well. That's because Interchange wouldn't otherwise know what part of the code is meant to be repeated for each row. In this example, there are two ON-MATCH blocks wrapped around the list to open and close a pair of HTML Unordered List tags. But you could also use them to open and close tables, paragraphs, or whatever.

Leave a Reply

Search
Categories