<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Words, punctuated &#187; SQL</title>
	<atom:link href="http://probertson.com/articles/category/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://probertson.com</link>
	<description>Thoughts on web development, user-centered design, code, etc. by Paul Robertson</description>
	<lastBuildDate>Mon, 30 Aug 2010 16:38:38 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Data &#8220;paging&#8221; in AIR SQLite</title>
		<link>http://probertson.com/articles/2010/04/07/data-paging-in-air-sqlite/</link>
		<comments>http://probertson.com/articles/2010/04/07/data-paging-in-air-sqlite/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 19:25:10 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Articles by Paul]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/?p=435</guid>
		<description><![CDATA[I got an interesting question a few days ago that I thought I&#8217;d share:
My application has thousands of records in one particular table that I need to populate the display with. I was wondering if I can implement paging to speed up the retrieval of those records?
In fact he specifically wanted to know if it [...]]]></description>
			<content:encoded><![CDATA[<p>I got an interesting question a few days ago that I thought I&#8217;d share:</p>
<blockquote><p>My application has thousands of records in one particular table that I need to populate the display with. I was wondering if I can implement paging to speed up the retrieval of those records?</p></blockquote>
<p class="editornote">In fact he specifically wanted to know if it was possible to do data paging with the SQLRunner class in my <a href="/projects/air-sqlite/">air-sqlite library</a>. The answer is yes it works, without even needing any changes to the library. See below for how to do that.</p>
<p>The easiest way to implement data paging (in other words, getting only a subset of a query&#8217;s results at a time) in a <code>SELECT</code> statement is to use the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/localDatabaseSQLSupport.html#select"><code>LIMIT..OFFSET</code> clause</a> in the <code>SELECT</code> statement.</p>
<p>In summary, you can put a <code>LIMIT</code> clause at the end of a <code>SELECT</code> statement and the result set will only include the specified number of rows:</p>
<pre class="brush:sql">SELECT * FROM myTable
LIMIT 3</pre>
<p>Then to get the next 3 rows, you add an <code>OFFSET</code> value:</p>
<pre class="brush:sql">SELECT * FROM myTable
LIMIT 3 OFFSET 3</pre>
<p>Fortunately, you can use statement parameters for the LIMIT and OFFSET values (although the docs don&#8217;t mention this &#8212; shame on me!):</p>
<pre class="brush:sql">SELECT * FROM myTable
LIMIT :limit OFFSET :offset</pre>
<p>Then you just specify values for those parameters and you&#8217;re good to go.</p>
<p>I tested this using the SQLRunner class by adding a <a href="http://github.com/probertson/air-sqlite/blob/master/tests/tests/com/probertson/data/SQLRunnerExecute.as">new set of unit tests</a> and it worked just fine without any changes to the library. (Hooray for unit tests and FlexUnit support in Flash Builder 4 &#8212; they made it nice and easy to test this out since I already had the infrastructure in place.)</p>
<p>Here is <a href="http://github.com/probertson/air-sqlite/blob/master/tests/sql/LoadRowsParameterizedLimitOffset.sql">the SQL statement I used for the unit test</a> using <code>LIMIT..OFFSET</code> with parameters:</p>
<pre class="brush:sql">SELECT colString,
colInt
FROM main.testTable
LIMIT :limit OFFSET :offset</pre>
<p>And here is <a href="http://github.com/probertson/air-sqlite/blob/master/tests/tests/com/probertson/data/SQLRunnerExecute.as#L125">the line of code that calls the statement</a> (modified slightly for readability). <code>test_result</code> is the result handler function. The parameters object specifies that I want 7 result rows, starting with row number 3 (i.e. skipping 2):</p>
<pre class="brush:actionscript3">_sqlRunner.execute(SQL, {limit:7, offset:2}, test_result);</pre>
<p class="editornote">As <a href="#comment-74422">Peter points out in the comments</a>, another approach to do something similar to data paging with AIR is to specify a number of rows to retrieve as the first argument to the <code>SQLStatement.execute()</code> method, then call the <code>SQLStatement.next()</code> method to retrieve additional rows from the same statement. This technique is <a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7d4c.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7d46">described in the documentation</a> so I won&#8217;t go into more detail about it here except to say that it does have a couple of drawbacks (mentioned in my comment below) that make it less suitable for data paging (but still very useful).</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2010/04/07/data-paging-in-air-sqlite/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>AIR SQLite library updates</title>
		<link>http://probertson.com/articles/2010/04/02/air-sqlite-library-updates/</link>
		<comments>http://probertson.com/articles/2010/04/02/air-sqlite-library-updates/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 09:18:14 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/?p=432</guid>
		<description><![CDATA[A couple of people have reported a bug in my AIR SQLite utility library. I also recently used it to help build a Robotlegs demo app for the 360&#124;Flex Robotlegs training, and in the process I discovered a missing feature I needed (namely, the ability to get back the SQLResult objects after running a batch [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of people have reported a <a href="http://github.com/probertson/air-sqlite/issues/closed/#issue/1">bug</a> in my <a href="/projects/air-sqlite/">AIR SQLite utility library</a>. I also recently used it to help build a Robotlegs demo app for the 360|Flex Robotlegs training, and in the process I discovered a missing feature I needed (namely, the ability to get back the SQLResult objects after running a batch of statements using <code>SQLRunner.executeModify()</code>).</p>
<p><strong>Warning!</strong> To add the missing feature I had to introduce a non-backwards-compatible api change. Read the details in the <a href="/projects/air-sqlite/#history">project history</a>.</p>
<p>So, the bug is <a href="http://github.com/probertson/air-sqlite/commit/09f2e5cd8ea2c854e5a28475a0fd19f12526e44b">fixed</a>, the feature is <a href="http://github.com/probertson/air-sqlite/commit/27fbeab18a2e8bc1bff194cbc669e9e64c5dd822">added</a>, the version number is incremented (0.1.1 beta), and the <a href="http://github.com/probertson/air-sqlite">code</a> and <a href="http://github.com/probertson/air-sqlite/downloads">SWC</a> are live on Github.</p>
<p><a href="http://github.com/probertson/air-sqlite/downloads">Download the version 0.1.1 SWC</a></p>
<p><a href="/projects/air-sqlite/#history">Read about the changes</a></p>
<p>In conjunction with the release I also added a couple of new examples to the <a href="/projects/air-sqlite/">project page</a>, including a <a href="/projects/air-sqlite/#shortexamples">&#8220;bare bones&#8221; code only example</a> for quick starters, and links to an <a href="/projects/air-sqlite/#robotlegsexamples">example of using the library in a Robotlegs application</a> (the example app from the 360|Flex training).</p>
<p>Enjoy, and as always feel free to report problems as <a href="http://github.com/probertson/air-sqlite/issues">issues in Github</a> or in the <a href="/projects/air-sqlite/#respond">comments on the project page</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2010/04/02/air-sqlite-library-updates/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>New project: AIR SQLite utilities</title>
		<link>http://probertson.com/articles/2010/02/03/new-project-air-sqlite-utilities/</link>
		<comments>http://probertson.com/articles/2010/02/03/new-project-air-sqlite-utilities/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 20:44:55 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[AS3]]></category>
		<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Application Design]]></category>
		<category><![CDATA[Articles by Paul]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/?p=367</guid>
		<description><![CDATA[I&#8217;m excited to announce that I&#8217;m &#8220;officially&#8221; releasing a new open-source project that I&#8217;ve been using on personal and work projects for over a year.
For lack of a better name, I call it my &#8220;AIR SQLite utility library&#8221;
The code currently contains one major piece of functionality (well, two different variations on one bit of functionality), [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m excited to announce that I&#8217;m &#8220;officially&#8221; releasing a new open-source project that I&#8217;ve been using on personal and work projects for over a year.</p>
<p>For lack of a better name, I call it my &#8220;<a href="/projects/air-sqlite/">AIR SQLite utility library</a>&#8221;</p>
<p>The code currently contains one major piece of functionality (well, two different variations on one bit of functionality), which is a SQL &#8220;query runner&#8221; library. This is a wrapper for the AIR SQL classes that allows you to run a SQL statement by just passing a few bits of information:</p>
<ul>
<li>The text of the SQL statement itself</li>
<li>An object containing properties with the values for any statement parameters in the SQL</li>
<li>A Function to call when the operation completes</li>
<li>A failure Function</li>
<li>(optionally) a class to use as the data type for the data returned from a <code>SELECT</code> statement</li>
</ul>
<p>The library does all the work of creating SQLStatement objects and caching prepared queries, as well as pooling SQLConnection instances so you can execute multiple statements simultaneously. It also has a variation that allows you to specify a &#8220;batch&#8221; of statements to execute, and they are executed in order in a transaction.</p>
<p>I&#8217;ve also got an additional utility to add to the library. It&#8217;s a &#8220;database copy&#8221; utility that allows you to create a &#8220;deep copy&#8221; of a database &#8212; all it&#8217;s tables, views, etc. &#8212; with or without data. The key reason why this is useful is that you can use it to create an encrypted database from an unencrypted database (and vice-versa). It&#8217;s written and tested, but I decided to modify the structure slightly before releasing it, so it&#8217;s not checked in yet.</p>
<p>I&#8217;ve put the details about how it works and why it&#8217;s designed that way in <a href="/projects/air-sqlite/">the project page</a>. In case you&#8217;ve ever wondered how I design apps, I think the examples and this library give some insight into how I actually do my database-driven AIR app development. At least, how I structure the data-access part of my apps.</p>
<p>On (another) personal note, this project is also my first project that I&#8217;ve posted to <a href="http://github.com/probertson">my Github repository</a> (as opposed to projects I&#8217;ve forked). It was actually posted-but-not-advertised on Google code for a month or so, but I decided to move to Github because the collaboration and checkin-without-network-connection features are so awesome.</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2010/02/03/new-project-air-sqlite-utilities/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Multi-table INSERT using one SQL statement in AIR SQLite</title>
		<link>http://probertson.com/articles/2009/11/30/multi-table-insert-one-statement-air-sqlite/</link>
		<comments>http://probertson.com/articles/2009/11/30/multi-table-insert-one-statement-air-sqlite/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 06:00:08 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Articles by Paul]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/?p=343</guid>
		<description><![CDATA[This article describes a way that you can use a single INSERT statement to add data to multiple tables in the SQL dialect supported by the SQLite engine in Adobe AIR.
Normally in SQL, including in AIR&#8217;s built-in SQLite database engine, you can only add data to one table at a time using an INSERT statement. [...]]]></description>
			<content:encoded><![CDATA[<p>This article describes a way that you can use a single <code>INSERT</code> statement to add data to multiple tables in the SQL dialect supported by the SQLite engine in Adobe AIR.</p>
<p>Normally in SQL, including in AIR&#8217;s built-in SQLite database engine, you can only add data to one table at a time using an <code>INSERT</code> statement. In some cases, particularly when you&#8217;re doing a &#8220;bulk loading&#8221; operation such as importing data from a text file into a database, it&#8217;s convenient to be able to insert data into multiple tables using a single <code>INSERT</code> statement.</p>
<p>For example, suppose you have XML data to import into a database such as the following:</p>
<pre>&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;employees&gt;
    &lt;employee firstName=&quot;Bob&quot; lastName=&quot;Smith&quot;
        location=&quot;San Francisco&quot; country=&quot;USA&quot;/&gt;
    &lt;employee firstName=&quot;Harold&quot; lastName=&quot;Jones&quot;
        location=&quot;San Francisco&quot; country=&quot;USA&quot;/&gt;
    &lt;employee firstName=&quot;Tom&quot; lastName=&quot;Donovan&quot;
        location=&quot;Boston&quot; country=&quot;USA&quot;/&gt;
    &lt;employee firstName=&quot;Mike&quot; lastName=&quot;Wilson&quot;
        location=&quot;Calgary&quot; country=&quot;Canada&quot;/&gt;
    &lt;employee firstName=&quot;Steve&quot; lastName=&quot;Thomas&quot;
        location=&quot;London&quot; country=&quot;UK&quot;/&gt;
    &lt;employee firstName=&quot;Joe&quot; lastName=&quot;Nelson&quot;
        location=&quot;London&quot; country=&quot;UK&quot;/&gt;
    &lt;employee firstName=&quot;Juan&quot; lastName=&quot;Varga&quot;
        location=&quot;Buenos Aires&quot; country=&quot;Argentina&quot;/&gt;
    ...
&lt;/employees&gt;</pre>
<p>The XML data isn&#8217;t normalized, so there is duplicate data between the various records. We will import it into a database with the following (normalized) structure:</p>
<p><img src="/resources/2009/11/30/multi_table_insert_data_model.png" width="400" height="430" alt="Data model for the database" /></p>
<p>Assuming the data is going to be imported as a single user operation, it would be painful to need to prompt the user or throw errors for every duplicate entry.</p>
<p>Using the technique described here, you can use a single SQL statement to add an employee and if necessary any related data including office location and country. (You would still loop over the data and execute one <code>INSERT</code> statement per employee record &#8212; but you wouldn&#8217;t need to execute three <code>INSERT</code> statements per employee record, or need to check for duplicate office locations and countries for each employee record to be inserted.)</p>
<p>As mentioned above, this technique is probably only appropriate when you&#8217;re doing &#8220;bulk importing&#8221; of data. If you&#8217;re just adding a single conceptual record (even if it includes data in multiple tables) you&#8217;ll most likely want to use a series of <code>INSERT</code> statements to add the data, so that you can have more precise error checking and handling.</p>
<h2>How to do it</h2>
<p>In an attempt to &#8220;cut to the chase&#8221; I&#8217;m going to put the necessary code here. For more detailed explanations on how this works and why it&#8217;s necessary, see the &#8220;<a href="#details">details</a>&#8221; section below.</p>
<p>This technique for inserting data into multiple tables using a single SQL statement consists of three elements:</p>
<ol>
<li>A view in the database that groups the data to be inserted (from all the tables) into one &#8220;table&#8221;</li>
<li>An <code>INSERT</code> statement to add the data, using the view as the destination &#8220;table&#8221; in the <code>INSERT</code> statement. This is the <code>INSERT</code> statement that you&#8217;ll run from your application while importing the data</li>
<li>A trigger defined on the view, which runs when any <code>INSERT</code> statement is executed against the view. This trigger does the actual work of checking for existing data and inserting data into individual tables.</li>
</ol>
<p>Here&#8217;s the code for each part:</p>
<h3>A view grouping the data to insert</h3>
<p>This combines all the tables that potentially need data inserted into a single &#8220;table&#8221; for the <code>INSERT</code> statement. You run this statement once to create the view in the database.</p>
<pre>CREATE VIEW employees_for_insert AS
SELECT e.firstName,
    e.lastName,
    l.name AS locationName,
    c.name AS countryName
FROM employees e
    INNER JOIN locations l ON e.locationId = l.locationId
    INNER JOIN countries c ON l.countryId = c.countryId</pre>
<h3>An <code>INSERT</code> statement that &#8220;inserts&#8221; the data into the view</h3>
<p>This code isn&#8217;t actually run, but it passes all the data to the database engine for use in the trigger. You execute this SQL statement once for each record to add to the tables.</p>
<pre>INSERT INTO employees_for_insert
(
    firstName,
    lastName,
    locationName,
    countryName
)
VALUES
(
    :firstName,
    :lastName,
    :locationName,
    :countryName
)</pre>
<h3>An <code>INSTEAD OF</code> trigger defined on the view</h3>
<p>This is the code that actually runs when the <code>INSERT</code> statement above is executed. You run this code once to create the trigger. Then the database runs the code in the trigger body automatically. If a location or country doesn&#8217;t exist it is inserted. However, if they do exist, nothing happens (no duplicate record is created). Then the main employee record is inserted.</p>
<pre>CREATE TRIGGER insert_employees_locations_countries
INSTEAD OF INSERT
ON employees_for_insert

BEGIN

INSERT INTO countries (name)
SELECT NEW.countryName
WHERE NOT EXISTS
    (SELECT 1 FROM countries
     WHERE name = NEW.countryName);

INSERT INTO locations (name, countryId)
SELECT NEW.locationName, countries.countryId
FROM countries
WHERE countries.name = NEW.countryName
AND NOT EXISTS
    (SELECT locationId
     FROM locations
     WHERE name = NEW.locationName);

INSERT INTO employees (firstName, lastName, locationId)
SELECT NEW.firstName,
    NEW.lastName,
    locations.locationId
FROM locations
WHERE locations.name = NEW.locationName;

END</pre>
<h2 id="details">Details</h2>
<p>The SQL language is designed for working with relational databases, so in a SQL database you usually use multiple tables to represent a single piece of data. That means that in a normal scenario, if you want to add a new record to a table, you may need to add a new row of data to additional tables that the main data is related to.</p>
<p>In this example, we are using a database with the following structure:</p>
<p><img src="/resources/2009/11/30/multi_table_insert_data_model.png" width="400" height="430" alt="Data model for the database" /></p>
<p>This data represents employees in a large company that has multiple office locations, identified by records in the <code>locations</code> table. In fact, this company is an international company that has offices in different countries, including multiple offices in some countries (represented by the <code>countries</code> table.</p>
<p>Each employee is associated with their primary office location by the <code>locationId</code> field in the <code>employees</code> table, and each location is defined as being in a certain country by the <code>countryId</code> column in the <code>locations</code> table.</p>
<p>In order to add a new employee you would generally have to perform several steps:</p>
<ol>
<li>Check whether the country where the employee&#8217;s office is located exists in the <code>countries</code> table</li>
<li>If not, add it; if so, get its id to create the relationship with the <code>locations</code> table</li>
<li>Make sure the office location exists in the <code>locations</code> table</li>
<li>If necessary add the location record, and get its id to use in the employee record</li>
<li>Add the employee record to the <code>employees</code> table</li>
</ol>
<p>This is a fairly complicated process because a single SQL <code>INSERT</code> statement can only operate on one table at a time. In a simple case where you are adding a single employee record, this complexity isn&#8217;t unbearably difficult. You can execute the series of SQL statements in sequence in a single transaction. If an error occurs, you can break out of the sequence and display an error message or handle the error as desired.</p>
<p>However, if you&#8217;re importing a large set of data it&#8217;s not convenient to throw errors or display dialogs to the user. Instead, it would be nice to be able to just add any dependent data where appropriate, and insert all the data in one step.</p>
<p>The technique that&#8217;s described in this article makes use of database views and a SQLite feature known as <code>INSTEAD OF</code> triggers.</p>
<p>A <em>view</em> is a predefined <code>SELECT</code> statement that&#8217;s saved in a database so it can be used in queries as though it was a table. Because it usually includes data from multiple tables, and doesn&#8217;t necessarily include all the data from any given table, a view is generally read-only &#8212; you can use a <code>SELECT</code> statement to retrieve data from a view, but you can&#8217;t use an <code>INSERT</code>, <code>UPDATE</code>, or <code>DELETE</code> statement to modify the view data.</p>
<p>However, in SQLite (and consequently in AIR) you can define a special type of trigger that&#8217;s associated with a view known as an <code>INSTEAD OF</code> trigger. (A trigger is a set of SQL code that&#8217;s associated with a table. The code is executed when a data manipulation operation is performed on that table.) When a SQL statement attempts to perform an <code>INSERT</code>, <code>DELETE</code>, or <code>UPDATE</code> operation on the view that has an <code>INSTEAD OF</code> trigger defined for that particular operation, the trigger is executed <em>instead of</em> the specified operation. You can only define <code>INSTEAD OF</code> triggers on views (it wouldn&#8217;t make sense to use one for a table). For more information about triggers, see <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/localDatabaseSQLSupport.html#createTrigger">the Adobe AIR SQL reference documentation for the <code>CREATE TRIGGER</code> statement</a>.</p>
<p>In this example, a view is defined that includes all the data in all the tables that potentially need data inserted. When the <code>INSERT</code> statement is executed the database runs the trigger instead. The trigger contains code that checks whether related data in the locations and countries tables already exists, and adds it if necessary. Then it adds the employee record with the related key values.</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2009/11/30/multi-table-insert-one-statement-air-sqlite/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>&#8220;Adobe AIR data privacy and security&#8221; - slides, notes, links</title>
		<link>http://probertson.com/articles/2009/06/09/adobe-air-data-privacy-and-security-slides-notes-links/</link>
		<comments>http://probertson.com/articles/2009/06/09/adobe-air-data-privacy-and-security-slides-notes-links/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 17:03:48 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Application Design]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Presentations]]></category>
		<category><![CDATA[Privacy/security]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/?p=279</guid>
		<description><![CDATA[On May 20, 2009 at the 360&#124;Flex conference in Indianapolis I gave a presentation titled &#8220;Adobe AIR data privacy and security.&#8221; As I always do (and after a bit of a delay), here are the slides from my presentation. I&#8217;ve added fairly lengthy notes to the slides (I had to make the font smaller so [...]]]></description>
			<content:encoded><![CDATA[<p>On May 20, 2009 at the 360|Flex conference in Indianapolis I gave a presentation titled &#8220;Adobe AIR data privacy and security.&#8221; As I always do (and after a bit of a delay), here are the slides from my presentation. I&#8217;ve added fairly lengthy notes to the slides (I had to make the font smaller so they&#8217;d fit on the pages) so it&#8217;s more than just bullet points.</p>
<p><a href="/resources/2009/06/09/air-data-privacy-security-slides-links.zip">Adobe AIR data privacy and security slides, notes, and links</a> (1 MB .zip)</p>
<p>As a side note for those who actually attended the presentation, in retrospect I think I over-emphasized the security concerns and didn&#8217;t emphasize enough that there are plenty of use cases for which AIR is definitely secure &#8212; especially in the case where you need to keep the user&#8217;s private data secure. Hopefully the notes that accompany the slides help to clarify this somewhat.</p>
<p>I also used and referred to a number of resources in my presentation, which are listed below. The download .zip with the slides also includes an html page with all these links.</p>
<h2>Introduction</h2>
<ul>
<li>&quot;<a href="http://tv.adobe.com/#vi+f15384v1025">Maintaining security with Adobe AIR</a>&quot; by Ethan Malasky and Peleus Uhley (Adobe MAX 2008)</li>
</ul>
<h2>Background</h2>
<ul>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7fa3.html">AIR security</a>&quot; (Adobe AIR documentation)</li>
<li>&quot;<a href="http://blogs.adobe.com/simplicity/2009/03/why_air_does_not_include_your_favorite_feature.html">Why Adobe AIR Doesn&#8217;t (Yet) Include the Feature You Most Want</a>&quot; by Oliver Goldman</li>
<li>&quot;<a href="http://tv.adobe.com/#vi+f15384v1102">Understanding the Flash Player Security Model</a>&quot; by Deneb Meketa (Adobe MAX 2008)</li>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS34990ABF-C893-47ec-B813-9C9D9587A398.html">Considerations for using encryption with a database</a>&quot; (Adobe AIR documentation)</li>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118676a5be7-8000.html">Using digital rights management</a>&quot; (Adobe AIR documentation)</li>
<li>Operating system security (user and &quot;admin&quot; rights)
<ul>
<li>&quot;<a href="http://blogs.adobe.com/simplicity/2009/04/what_are_administrative_rights.html">What are Adminstrative Rights, Anyway?</a>&quot; by Oliver Goldman</li>
<li>&quot;<a href="http://blogs.adobe.com/simplicity/2009/04/does_installing_an_air_app_require_admin_rights.html">Does Installing an AIR Application Require Admin Rights?</a>&quot; by Oliver Goldman</li>
</ul>
</li>
<li>Source code visibility
<ul>
<li><a href="http://www.buraks.com/asv/">Action Script Viewer (ASV)</a></li>
<li>&quot;<a href="http://www.gotoandlearn.com/play?id=70">Ethical SWF Decompiling</a>&quot; by Lee Brimelow</li>
<li><a href="http://www.nitrolm.com/home">Nitro-LM</a></li>
</ul>
</li>
<li>Encryption: ActionScript  crypto libraries:
<ul>
<li><a href="http://code.google.com/p/as3crypto/">as3crypto</a></li>
<li><a href="http://labs.adobe.com/wiki/index.php/Alchemy:Libraries">OpenSSL (partially) cross-compiled to ActionScript</a> using <a href="http://labs.adobe.com/technologies/alchemy/">Alchemy</a></li>
</ul>
</li>
</ul>
<h2>AIR application installation</h2>
<ul>
<li>Sign your app with a trusted cert
<ul>
<li>&quot;<a href="http://www.ddj.com/architect/210004209">Code Signing in Adobe AIR</a>&quot; by Oliver Goldman</li>
<li>&quot;<a href="http://www.stage.adobe.com/devnet/air/articles/signing_air_applications.html">Digitally signing Adobe AIR applications</a>&quot; by Todd Prekaski</li>
<li>Promotion: get a free signing certificate (while supplies last) by submitting your app to the <a href="http://www.adobe.com/go/airmarketplace">Adobe AIR marketplace</a></li>
</ul>
</li>
<li>Plan for updates
<ul>
<li>&quot;<a href="http://www.adobe.com/devnet/air/articles/tips_building_air_apps.html">Building AIR applications that can be easily updated</a>&quot; by David Deraedt</li>
<li>&quot;<a href="http://www.adobe.com/devnet/air/flex/quickstart/update_framework.html">Using the Adobe AIR update framework</a>&quot; Quick Start article by Jeff Swartz (Adobe AIR documentation)</li>
</ul>
</li>
</ul>
<h2>Modular applications</h2>
<ul>
<li>Sandbox bridge
<ul>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7e5c.html">Scripting between content in different domains</a>&quot; (Adobe AIR documentation)</li>
</ul>
</li>
<li>XML signature validation
<ul>
<li>&quot;<a href="http://www.adobe.com/devnet/air/flex/quickstart/xml_signatures.html">Creating and validating XML signatures</a>&quot; by Joe Ward</li>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WSe3d2d529026165536d4beb2c11c33737198-8000.html">Using the XML signature validation classes</a>&quot; (Adobe AIR documentation)</li>
<li>&quot;<a href="http://livedocs.adobe.com/flex/3/langref/index.html?flash/security/package-detail.html&amp;flash/security/class-list.html">flash.security package</a>&quot; reference (Adobe AIR documentation)</li>
</ul>
</li>
</ul>
<h2>Local shared objects</h2>
<p>[No links]</p>
<h2>Encrypted Local Store</h2>
<ul>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7e31.html">Storing encrypted data</a>&quot; (Adobe AIR documentation)</li>
<li>&quot;<a href="http://livedocs.adobe.com/flex/3/langref/index.html?flash/data/EncryptedLocalStore.html&amp;flash/data/class-list.html">EncryptedLocalStore class</a>&quot; reference (Adobe AIR documentation)</li>
</ul>
<h2>Local files</h2>
<p>[No links]</p>
<h2>Local SQL database (SQLite)</h2>
<ul>
<li>SQL injection attack
<ul>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7d42.html">Using parameters in statements</a>&quot; (Adobe AIR documentation)</li>
<li>&quot;<a href="http://livedocs.adobe.com/flex/3/langref/index.html?flash/data/SQLStatement.html#parameters&amp;flash/data/class-list.html">SQLStatement.parameters property</a>&quot; reference (Adobe AIR documentation)</li>
</ul>
</li>
<li>Encrypted database
<ul>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS8AFC5E35-DC79-4082-9AD4-DE1A2B41DAAF.html">Using encryption with SQL databases</a>&quot; (Adobe AIR documentation)</li>
<li>&quot;<a href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS44EC31A7-61B1-4e0a-8C61-D720AA95DE03.html">Using the EncryptionKeyGenerator class to obtain a secure encryption key</a>&quot; (Adobe AIR documentation)</li>
<li><a href="http://code.google.com/p/as3corelib/">as3corelib project</a> (includes the EncryptionKeyGenerator class and hashing algorithms</li>
</ul>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2009/06/09/adobe-air-data-privacy-and-security-slides-notes-links/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Now updated: &#8220;Doppler&#8221; AIR SQL query testing tool</title>
		<link>http://probertson.com/articles/2009/01/26/updates-to-doppler-air-sql-query-testing-tool/</link>
		<comments>http://probertson.com/articles/2009/01/26/updates-to-doppler-air-sql-query-testing-tool/#comments</comments>
		<pubDate>Tue, 27 Jan 2009 06:20:45 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Elsewhere on the web]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Sites to remember]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/?p=224</guid>
		<description><![CDATA[I just wanted to write a quick note to say that I&#8217;ve released an update to my &#8220;Doppler&#8221; AIR SQL admin tool. You can get it from the Doppler project page. (I&#8217;ve been working on an actual real application, one with a fair amount of database work, so naturally I&#8217;ve found motivation to fix some [...]]]></description>
			<content:encoded><![CDATA[<p>I just wanted to write a quick note to say that I&#8217;ve released an update to my &#8220;Doppler&#8221; AIR SQL admin tool. You can get it from the <a href="/projects/doppler-air-sql-admin-tool/">Doppler project page</a>. (I&#8217;ve been working on an actual real application, one with a fair amount of database work, so naturally I&#8217;ve found motivation to fix some lingering bugs and add some missing functionality.)</p>
<p>As with previous versions, if you&#8217;ve been using the app you&#8217;ll need to uninstall it before installing the new version. Someday I&#8217;ll add updating support, but I&#8217;m not going to promise anything real soon.</p>
<p>Along with this release, I&#8217;ve also made a change to how I describe the tool, and to my future intentions for it. I&#8217;ve always had it in my mind to make this a full-fledged database admin tool, similar to the tools that come with SQL Server or other enterprise databases. However, time has obviously not allowed me to do that, and in the mean time other tools have been released by other developers. I&#8217;ve found one, <a href="http://www.dehats.com/drupal/?q=node/58">David Deraedt’s “Lita” SQLite admin tool</a> that is sufficiently mature that I use it in my day-to-day work now and it definitely beats doing things by hand! There are still improvements to be made and features to be added, but when I&#8217;ve reported bugs and feature requests he&#8217;s been quick to respond and release updates.</p>
<p>So while I&#8217;m sure nobody&#8217;s been holding their breath waiting for me to finish the &#8220;admin tool&#8221; portion of my app, I just wanted to clarify the new direction I&#8217;m taking it &#8212; or rather, the fact that I&#8217;m not planning to take it in as many new directions! (Hence the change in title for the project from &#8220;AIR SQL admin tool&#8221; to &#8220;AIR SQL query testing tool.&#8221;)</p>
<p>That doesn&#8217;t mean I&#8217;m done developing this tool by any means. In past jobs where I did heavy database development, and in a project I&#8217;m currently working on that involves heavy database development, I find it very useful to have two different kinds of database tools &#8212; one for creating and managing database objects and structure, and another for testing queries. While Lita does in fact have a tab for testing queries, I personally find Doppler to be a bit (not a lot, but a bit =) more developed in that specific area. On the other hand, Lita certainly does a lot in the db management space that Doppler doesn&#8217;t do. So I find the tools very complementary in terms of my actual development work.</p>
<p>As always, I welcome feedback, questions, thoughts, etc. And thanks to everyone who&#8217;s already reported bugs and offered suggestions!</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2009/01/26/updates-to-doppler-air-sql-query-testing-tool/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>360&#124;Flex slides for &#8220;AIR SQLite: An optimization conversation&#8221;</title>
		<link>http://probertson.com/articles/2008/08/22/360flex-slides-for-air-sqlite-optimization-conversation/</link>
		<comments>http://probertson.com/articles/2008/08/22/360flex-slides-for-air-sqlite-optimization-conversation/#comments</comments>
		<pubDate>Sat, 23 Aug 2008 00:16:24 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Articles by Paul]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Presentations]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/?p=188</guid>
		<description><![CDATA[Updates (Oct. 30, 2008): The video of my presentation has been posted, so I added a link to it at the bottom of this post. Also, I just learned about another AIR-based SQLite admin tool which looks interesting, so I added it to the list of resources even though it&#8217;s obviously not discussed in the [...]]]></description>
			<content:encoded><![CDATA[<p class="editornote">Updates (Oct. 30, 2008): The video of my presentation has been posted, so I added a link to it at the bottom of this post. Also, I just learned about another AIR-based SQLite admin tool which looks interesting, so I added it to the list of resources even though it&#8217;s obviously not discussed in the presentation.</p>
<p>As I mentioned briefly before, this week I presented at the 360|Flex San Jose (August 2008) conference. My presentation was titled &#8220;Adobe AIR SQLite: An optimization conversation.&#8221; As I mentioned in the presentation, the term &#8220;optimization&#8221; could mean a few different things &#8212; for example, optimization meaning improving performance, or optimization meaning improving developer productivity. While my presentation focused mostly on the first type of optimization, I included suggestions for tools, libraries, and strategies that fall in the &#8220;developer productivity&#8221; type of optimization as well.</p>
<p>Anyway, as always I&#8217;m happy to make my presentation materials available. Here are the slides (with some notes) from my presentation:</p>
<p><a href="/resources/2008/08/22/air_sqlite_optimization_slides.zip">&#8220;Adobe AIR SQLite: An optimization conversation&#8221; slides</a> (PDF in .zip - 504kb)</p>
<p>I don&#8217;t really have any specific code examples, apart from what&#8217;s in the slides, so there&#8217;s no &#8220;source code&#8221; download. However, I did link to a lot of external tools and resources (including a few of my own). To save you the trouble of digging into the PDF, here are the links:</p>
<p>Tools</p>
<ul>
<li><a href="http://coenraets.org/blog/2008/02/air-based-sqlite-admin-updated-for-beta-3/">Cristophe Coenraets&#8217; &#8220;SQLite Admin&#8221;</a></li>
<li><a href="/projects/doppler-air-sql-admin-tool/">My tool for testing queries</a></li>
<li><a href="http://www.dehats.com/drupal/?q=node/59">&#8220;Lita&#8221; by David Deraedt</a> (I learned about this one after the presentation, so it&#8217;s not discussed in my slides/video, but I thought it&#8217;d be worth mentioning anyway.)</li>
</ul>
<p>Application architecture/patterns/libraries</p>
<ul>
<li><a href="http://www.peterelst.com/blog/2008/04/07/introduction-to-sqlite-in-adobe-air/">SQLite MXML wrapper classes</a> (Peter Elst)</li>
<li><a href="http://www.brandonellis.org/?p=49">Data access layer</a> (Brandon Ellis)</li>
<li><a href="http://code.google.com/p/asqlib/">asqlib SQL statement generator</a> (Miran Loncaric)</li>
<li>&#8220;Command&#8221; classes (me) as <a href="/projects/addressbook/">demonstrated by my AddressBook sample application</a></li>
<li><a href="http://code.google.com/p/air-activerecord/">AIR ActiveRecord source</a> and <a href="http://jacwright.com/blog/79/air-activerecord-is-open-source/">blog post explaining its usage</a> (Jacob Wright)</li>
<li><a href="http://www.ericfeminella.com/blog/2008/06/22/air-cairngorm-20/">AIR SQLite Cairngorm services</a> (Eric Feminella)</li>
<li>Connection and statement pools, mentioned (with source code) in the article <a href="http://www.adobe.com/devnet/air/flex/articles/air_sql_operations.html">User experience considerations with SQLite operations</a> (Daniel Rinehart)</li>
</ul>
<p>Finally, as you may have heard, Adobe sponsored the recording of every presentation at 360|Flex, and they&#8217;re all going to be made available free of charge via a channel in Adobe Media Player. They&#8217;re rolling them out in phases, <span class="cut">and mine isn&#8217;t available yet. When it is, I&#8217;ll update this post with the video as well.</span> Update: the video is <a href="http://onflash.org/ted/2008/10/360flex-sj-2008-air-sqlite-optimization.php">now available on Ted Patrick&#8217;s blog</a> as well as in Adobe Media Player.</p>
<p>In the mean time, 360|Flex was full of awesome presentations. I wasn&#8217;t able to get to all the ones I wanted to see, due to conflicts and me trying to finish up preparation for my presentation. So I&#8217;m going to be spending some time watching many of those videos as well. If you&#8217;d like to see the videos, Ted Patrick has posted instructions on his blog:</p>
<p><a href="http://www.onflex.org/ted/2008/08/360flex-sessions-media-rss-feed.php">How to view 360|Flex San Jose 8/08 session videos in Adobe Media Player</a></p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2008/08/22/360flex-slides-for-air-sqlite-optimization-conversation/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>AIR embedded SQL database: What&#8217;s new in beta 2</title>
		<link>http://probertson.com/articles/2007/10/09/air-sql-database-what-s-new-in-beta-2/</link>
		<comments>http://probertson.com/articles/2007/10/09/air-sql-database-what-s-new-in-beta-2/#comments</comments>
		<pubDate>Tue, 09 Oct 2007 23:41:55 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[AS3]]></category>
		<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Articles by Paul]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/articles/2007/10/09/air-sql-database-what-s-new-in-beta-2/</guid>
		<description><![CDATA[Now that the roar of MAX is over, and since AIR public beta 2 is now available on Adobe Labs, I thought I&#8217;d highlight what&#8217;s new in beta 2 specifically around the embedded SQL database in AIR:

Synchronous database operations
Schema API (database instrospection)
Additional data types
Other new documentation
Bug fixes

Synchronous database operations
From the various public and internal feedback [...]]]></description>
			<content:encoded><![CDATA[<p>Now that the roar of MAX is over, and since <a href="http://labs.adobe.com/technologies/air/">AIR public beta 2</a> is now available on Adobe Labs, I thought I&#8217;d highlight what&#8217;s new in beta 2 specifically around the embedded SQL database in AIR:</p>
<ul>
<li><a href="#sync">Synchronous database operations</a></li>
<li><a href="#schema">Schema API (database instrospection)</a></li>
<li><a href="#types">Additional data types</a></li>
<li><a href="#docs">Other new documentation</a></li>
<li><a href="#bugs">Bug fixes</a></li>
</ul>
<h2 id="sync">Synchronous database operations</h2>
<p>From the various public and internal feedback forums I&#8217;ve seen (discussion lists, mailing lists, etc.) this is definitely the most-requested feature from beta 1 (at least related to the embedded database). It&#8217;s in there now &#8212; when you instantiate a SQLConnection object, just add <code>true</code> as a constructor argument and all the operations (including SQL statements) that are executed through that SQLConnection will run synchronously.</p>
<p>The good news is it&#8217;s really very similar to the way things worked in beta 1, so if you&#8217;ve already been doing things asynchronously you won&#8217;t have to do much to get going with synchronous db operations. Note that a lot of people have referred to this as a &#8220;synchronous API&#8221; but in fact there isn&#8217;t a separate synchronous API &#8212; it&#8217;s the same API, with the exception of the single <code>SQLConnection()</code> argument.</p>
<p>To learn more, here&#8217;s the place where you should probably start: Developing AIR Applications > Working with files and data > Working with local SQL databases > Using synchronous and asynchronous database operations (<a href="http://livedocs.adobe.com/labs/air/1/devappsflex/SQL_23.html#1096192">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappshtml/SQL_23.html#1096192">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappsflash/SQL_23.html#1096192">Flash</a>)</p>
<h2 id="schema">Schema API (database instrospection)</h2>
<p>One limitation that developers pointed out in beta 1 was that there wasn&#8217;t any built-in way to get information about the structure of a database, tables, etc. In beta 2, there&#8217;s a new set of classes that can be used to get at that information. There isn&#8217;t any information in the developers guide about this yet, but in this case you can figure it out by looking in the API reference. The best place to start is probably with the <code>SQLConnection.loadSchema()</code> method (<a href="http://livedocs.adobe.com/labs/flex3/langref/flash/data/SQLConnection.html#loadSchema()">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/jslr/flash/data/SQLConnection.html#loadSchema()">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/aslr/flash/data/SQLConnection.html#loadSchema()">Flash</a>).</p>
<p>There are also several new classes that are used for the various types of schema information you can get:</p>
<ul>
<li>SQLTableSchema (<a href="http://livedocs.adobe.com/labs/flex3/langref/flash/data/SQLTableSchema.html">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/jslr/flash/data/SQLTableSchema.html">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/aslr/flash/data/SQLTableSchema.html">Flash</a>)</li>
<li>SQLViewSchema (<a href="http://livedocs.adobe.com/labs/flex3/langref/flash/data/SQLViewSchema.html">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/jslr/flash/data/SQLViewSchema.html">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/aslr/flash/data/SQLViewSchema.html">Flash</a>)</li>
<li>SQLIndexSchema (<a href="http://livedocs.adobe.com/labs/flex3/langref/flash/data/SQLIndexSchema.html">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/jslr/flash/data/SQLIndexSchema.html">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/aslr/flash/data/SQLIndexSchema.html">Flash</a>)</li>
<li>SQLTriggerSchema (<a href="http://livedocs.adobe.com/labs/flex3/langref/flash/data/SQLTriggerSchema.html">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/jslr/flash/data/SQLTriggerSchema.html">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/aslr/flash/data/SQLTriggerSchema.html">Flash</a>)</li>
<li>SQLColumnSchema (<a href="http://livedocs.adobe.com/labs/flex3/langref/flash/data/SQLColumnSchema.html">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/jslr/flash/data/SQLColumnSchema.html">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/aslr/flash/data/SQLColumnSchema.html">Flash</a>)</li>
</ul>
<h2 id="types">Additional data types</h2>
<p>Several ActionScript/JavaScript data types can now be used as column data types in the <code>CREATE TABLE</code> statements. When you specify one of these data types for your column, you can pass an instance of that type into an SQL statement (using a parameter) and it will property store and retrieve the data as the ActionScript/JavaScript data type. The new supported data types are:</p>
<ul>
<li>Boolean</li>
<li>Date</li>
<li>XML</li>
</ul>
<p>More information about these data types can be found in the developers guide section &#8220;Working with database data types&#8221; (<a href="http://livedocs.adobe.com/labs/air/1/devappsflex/SQL_19.html#1095961">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappshtml/SQL_19.html#1095961">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappsflash/SQL_19.html#1095961">Flash</a>) and in the language reference appendix &#8220;SQL support in local databases&#8221; (specifically the &#8220;<a href="http://livedocs.adobe.com/labs/flex3/langref/localDatabaseSQLSupport.html#dataTypes">data type support</a>&#8221; section). (Note that the link goes to the Flex language reference. I couldn&#8217;t find that appendix in the Flash or HTML/JS versions, although the content is identical for all of them since it&#8217;s really just talking about SQL.)</p>
<h2 id="docs">Other new documentation</h2>
<p>Although I did take several weeks between beta 1 and beta 2 to move from Indiana to the San Francisco bay area, I did get some additional documentation written. If I remember right, these are the sections that are new for beta 2 (other than the ones I&#8217;ve already mentioned above):</p>
<ul>
<li>Using parameters in statements (<a href="http://livedocs.adobe.com/labs/air/1/devappsflex/SQL_10.html">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappshtml/SQL_10.html">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappsflash/SQL_10.html">Flash</a>)</li>
<li>Strategies for working with SQL databases (<a href="http://livedocs.adobe.com/labs/air/1/devappsflex/SQL_26.html#1084956">Flex</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappshtml/SQL_26.html#1084956">HTML/JavaScript</a> | <a href="http://livedocs.adobe.com/labs/air/1/devappsflash/SQL_26.html#1084956">Flash</a>) - new sections on improving performance and best practices</li>
<li>&#8230; and more! (improvements and corrections in various other sections)</li>
</ul>
<h2 id="bugs">Bug fixes</h2>
<p>Need I say more? =)</p>
<p>(In seriousness, lots of bugs were fixed, so if there&#8217;s an issue you were running into, try it out in beta 2 and <a href="http://www.adobe.com/go/wish/">let us know</a> if it&#8217;s still not working.)</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2007/10/09/air-sql-database-what-s-new-in-beta-2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Asynchronous database operations with AIR, SQL, and JavaScript</title>
		<link>http://probertson.com/articles/2007/08/10/asynch-db-queries-air-javascript/</link>
		<comments>http://probertson.com/articles/2007/08/10/asynch-db-queries-air-javascript/#comments</comments>
		<pubDate>Fri, 10 Aug 2007 17:13:58 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Articles to remember]]></category>
		<category><![CDATA[Elsewhere on the web]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/articles/2007/08/10/asynch-db-queries-air-javascript/</guid>
		<description><![CDATA[Justin (&#8220;AlternateIdea&#8221;) has a nice, fairly technical write up of dealing with asynchronous operations when you&#8217;re using the AIR SQL database with JavaScript.
I admit, my JavaScript is much rustier than my ActionScript/Flex, so I&#8217;m glad to see these sorts of things &#8212; it helps me to see what patterns and approaches work for the larger-than-you-might-imagine [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://alternateidea.com/">Justin (&#8220;AlternateIdea&#8221;)</a> has <a href="http://alternateidea.com/blog/articles/2007/8/7/asynchronous-sqlite-adobe-air">a nice, fairly technical write up of dealing with asynchronous operations when you&#8217;re using the AIR SQL database with JavaScript</a>.</p>
<p>I admit, my JavaScript is much rustier than my ActionScript/Flex, so I&#8217;m glad to see these sorts of things &#8212; it helps me to see what patterns and approaches work for the larger-than-you-might-imagine JavaScript AIR developer audience.</p>
<p class="editornote">Update: added links, so that you can actually find the article (Doh!)</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2007/08/10/asynch-db-queries-air-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Danny-T on database fundamentals for AIR</title>
		<link>http://probertson.com/articles/2007/06/26/database-fundamentals-for-air/</link>
		<comments>http://probertson.com/articles/2007/06/26/database-fundamentals-for-air/#comments</comments>
		<pubDate>Tue, 26 Jun 2007 20:12:09 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Application Design]]></category>
		<category><![CDATA[Articles to remember]]></category>
		<category><![CDATA[Elsewhere on the web]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/articles/2007/06/26/database-fundamentals-for-air/</guid>
		<description><![CDATA[Dan Thomas (&#8220;Danny-T&#8221;) has written up a nice concise intro to database concepts, geared toward working with databases in AIR. He ends it with a nice list of factors to consider in deciding whether to use a local database (with AIR&#8217;s local SQL database engine) or a remote database (available through the same mechanisms you&#8217;d [...]]]></description>
			<content:encoded><![CDATA[<p>Dan Thomas (&#8220;Danny-T&#8221;) has written up a nice <a href="http://danny-t.co.uk/index.php/2007/06/23/what-is-an-air-database/">concise intro to database concepts, geared toward working with databases in AIR</a><span id="more-147"></span>. He ends it with a nice list of factors to consider in deciding whether to use a local database (with AIR&#8217;s local SQL database engine) or a remote database (available through the same mechanisms you&#8217;d use in a browser-based Flex/Ajax app).</p>
<p>I definitely agree with his conclusion &#8212; one of the strengths of AIR is that you can use either, or both, of these approaches depending on the needs of your app.</p>
<p>As a side note, the AIR documentation also includes some introductory content on <a href="http://livedocs.adobe.com/labs/air/1/devappsflex/SQL_04.html">relational databases</a>, <a href="http://livedocs.adobe.com/labs/air/1/devappsflex/SQL_05.html">SQL</a>, and related concepts &#8212; although I intentionally kept it limited, since the topic of relational databases is so vast that many books have been written about the subject.</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2007/06/26/database-fundamentals-for-air/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Brandon Ellis&#8217;s DataAccess Utility class</title>
		<link>http://probertson.com/articles/2007/06/19/brandon-ellis-dataaccess-class/</link>
		<comments>http://probertson.com/articles/2007/06/19/brandon-ellis-dataaccess-class/#comments</comments>
		<pubDate>Tue, 19 Jun 2007 16:17:56 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Application Design]]></category>
		<category><![CDATA[Articles to remember]]></category>
		<category><![CDATA[Elsewhere on the web]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/articles/2007/06/19/brandon-ellis-dataaccess-class/</guid>
		<description><![CDATA[If you&#8217;re looking to simplify the local database access part of your AIR app, this might be the ticket. Brandon Ellis has written a no-frills wrapper class for AIR local database operations. The biggest benefit it provides is that if you add, delete, or update data in a table, it automatically updates whatever component is [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re looking to simplify the local database access part of your AIR app, this might be the ticket. Brandon Ellis has written a <a href="http://www.brandonellis.org/?p=49">no-frills wrapper class for AIR local database operations</a>. The biggest benefit it provides is that if you add, delete, or update data in a table, it automatically updates whatever component is displaying the data from the related SELECT statement.</p>
<p>The part that caught my eye the most was that the wrapper class doesn&#8217;t dispatch any events to notify the view when the operations have completed. How, I asked myself, does it notify the view when the updated data loads? After a few seconds I realized the answer &#8212; it&#8217;s the magic of Flex data binding. The DataAccess class exposes the SELECT results as a property (<code>dbResult</code>) that&#8217;s a Flex ArrayCollection, and it&#8217;s marked <code>[Bindable]</code>. A Flex control can bind to that property as a data provider, and whenever the DataAccess instance reloads its data and updates the ArrayCollection. Then the Flex framework takes over, and the view gets updated automatically. Pretty slick; and it definitely saves a lot of event-handling code. So I guess seeing this in action gave me further appreciation for the power of data binding.</p>
<p>It has a couple of minor issues that I&#8217;ve noted in the comments on that page (but mostly they should be fairly easy to fix, if Brandon or someone else decides to do so).</p>
<p>(via: <a href="http://blog.halcyonsolutions.net/">Greg Hamer</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2007/06/19/brandon-ellis-dataaccess-class/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AIR, local SQL databases, and my role</title>
		<link>http://probertson.com/articles/2007/06/11/adobe-air-local-sql-databases-and-my-role/</link>
		<comments>http://probertson.com/articles/2007/06/11/adobe-air-local-sql-databases-and-my-role/#comments</comments>
		<pubDate>Mon, 11 Jun 2007 21:37:56 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[AS3]]></category>
		<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Articles by Paul]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Writing]]></category>
		<category><![CDATA[local SQL database]]></category>

		<guid isPermaLink="false">http://probertson.com/articles/2007/06/11/adobe-air-local-sql-databases-and-my-role/</guid>
		<description><![CDATA[As everyone knows, today Adobe released a public beta of AIR (formerly "Apollo"). As you likely know, since it was announced last week, one of the big new features in this release is an integrated database engine that allows AIR applications to create and use local SQL databases. I'm really excited about this, both because it's really awesome to be able to access a database directly from ActionScript, and (on a personal level) because it means I can finally talk about what I've been working on for the last couple of months. Yes, in fact, my latest assignment at Adobe primarily involves working on the AIR local SQL database functionality.]]></description>
			<content:encoded><![CDATA[<p>As everyone knows, today Adobe released a public beta of AIR (formerly &#8220;Apollo&#8221;). As you likely know, since it was announced last week, one of the big new features in this release is an integrated database engine that allows AIR applications to create and use local SQL databases.</p>
<p>Okay, that sounds really boring. But I don&#8217;t mean it to. I&#8217;m actually <em>incredibly</em> excited by this, because it makes it a lot easier for people like me, with web app experience but not desktop app experience, to create data-driven apps and store persistent data using techniques that I&#8217;m familiar with.</p>
<p>And, on a personal note, it means that I finally get to talk about what I&#8217;ve been working on for the last couple of months. If you actually follow my web site, you&#8217;ve probably picked up on the fact that I was heavily involved in the ActionScript-related documentation for the Flash CS3 release. Well, naturally, now that Flash CS3 is out the door, I&#8217;ve been moved onto another project &#8212; onto Apollo/AIR, specifically.</p>
<p>More specifically, since I&#8217;ve been programming SQL databases for many years, as part of my web app development work, I got pegged (well, I actually volunteered) to do the documentation and samples for the local SQL databases feature.</p>
<p>When I first read the spec for the feature, I was completely floored. I was expecting some minimal support for a few things, but what we&#8217;ve got is much more than I could come up with use cases for. Want a good idea of the breadth of the functionality that&#8217;s available? Spend some time reading &#8220;<a href="http://livedocs.adobe.com/labs/flex/3/langref/localDatabaseSQLSupport.html">SQL support in local databases</a>&#8221; (it&#8217;s an appendix of the AIR language reference). Views? Indexes? Triggers? They&#8217;re in there.</p>
<p>In case you don&#8217;t have a free few hours, I&#8217;ll just point out my favorite parts of the feature. These will probably be most meaningful if you&#8217;ve already faced the joy and pain of working with web-database apps, especially with an OOP language:</p>
<ul>
<li><code><a href="http://livedocs.adobe.com/labs/flex/3/langref/flash/data/SQLStatement.html#itemClass">SQLStatement.itemClass</a></code>: This was my immediate favorite. You specify a class, and SELECT statement result rows are automatically converted into instances of that class (saving lots of boilerplate code to loop through results and turn rows into instances of some other class). If I could have done this in ASP.NET, I&#8217;d probably have saved about 25% of the total code I wrote.</li>
<li><code><a href="http://livedocs.adobe.com/labs/flex/3/langref/flash/data/SQLStatement.html#prepare()">SQLStatement.prepare()</a></code> and <code><a href="http://livedocs.adobe.com/labs/flex/3/langref/flash/data/SQLStatement.html#parameters">SQLStatement.parameters</a></code>: Now that I&#8217;ve spent some time building apps and working with the code, I&#8217;ve gotten a lot of respect for this method. Basically, this is the way to create the equivalent of pre-compiled stored procedures for your AIR app.</li>
<li><code><a href="http://livedocs.adobe.com/labs/flex/3/langref/flash/data/SQLResult.html#lastInsertRowID">SQLResult.lastInsertRowID</a></code>: I had to lobby long and hard for this one, which, since I&#8217;m a remote employee, meant <em>lots</em> of email exchanges. Finally I managed to clearly articulate my reason, and sure enough, persistence paid off. If you&#8217;ve created a database app, chances are you&#8217;ve run into the case where you INSERT a row, and you need to get back the auto-generated primary key so that you can insert a related row. The <em>wrong</em> way to do it is <code>SELECT MAX(id_column) FROM table</code>. The right way, in AIR, is to use <code>lastInsertRowID</code>.</li>
</ul>
<p>I&#8217;m excited that I can talk about this now. I&#8217;ve got some samples, practices, and information that I&#8217;m looking forward to sharing. I&#8217;ll start with an answer to a question that I&#8217;ve seen asked around (well, mostly I&#8217;ve just seen misinformation, not people asking whether it&#8217;s right) about the relationship between the AIR local SQL database API and the Google Gears SQL database API:</p>
<ul>
<li>Does Apollo &#8220;include&#8221; part of Google Gears? - No. There is no shared code between AIR and Google Gears (with the possible exception noted in the next answer).</li>
<li>What do AIR and Google Gears have in common, then? - Both AIR and Google Gears let you create applications that access databases located on a users local machine. Both AIR and Google Gears chose to use SQLite, a free, public domain embedded SQL database engine, to provide that functionality. So whatever code AIR uses that hasn&#8217;t been modified from SQLite, is the same as the code that Google Gears uses that hasn&#8217;t been modified in its implementation of SQLite.</li>
<li>What&#8217;s this about AIR including the same database API as Google Gears? - To be honest, although I&#8217;ve been involved in the AIR database API for a while, the first I heard of Google Gears&#8217; database API was when the public announcements were made. Thinking back, I see now that discussions were going on for a while, and I even unknowingly provided some support to the management team and others who were involved in that discussion. Right now, although the underlying database engines are based on the same engine, since SQLite is written in C, any implementation that doesn&#8217;t use C/C++ needs to write its own API. The two implementations (Adobe&#8217;s and Google&#8217;s) weren&#8217;t developed together, and at this point (from what I&#8217;ve seen) the two APIs are pretty different. Case in point: synchronous versus asynchronous database operations. In Google Gears, data access operations are synchronous &#8212; calls to the database are blocking, meaning the runtime freezes at the line of code that called the database until the result is returned. In AIR, on the other hand, all data operations are asynchronous &#8212; you call <code>SQLStatement.execute()</code> to run a query, and when the result comes back an event listener function is called (at which point the result data can be accessed). That alone means a big difference in how you write code to work with the two systems.</li>
<li>So wait a minute, what about the whole &#8220;Adobe and Google are working together on the database API&#8221; thing? - Adobe and Google <em>are</em> having &#8220;discussions,&#8221; and (from what I&#8217;ve heard) the plan is to hopefully make the APIs the same or similar enough that a developer who writes data access code for Google Gears will have an easy time writing data access code for AIR (and vice versa). In addition, since the SQL part of both runtimes really is dependent on SQLite much more than the particular runtime implementation, and SQL code probably is interchangeable between the two runtimes, assuming the same database schema etc.</li>
</ul>
<p>So from me, and the other engineers and stakeholders inside Adobe, please try out the local SQL database functionality of Apollo, and <strong>please</strong> let us know what we can do to make it better. In particular, let me know what is missing or what you&#8217;d like to see in terms of documentation and samples &#8212; but don&#8217;t limit yourself to that. <em>Please share your comments/suggestions!</em></p>
<h2 id="personal">On a more personal note&#8230;</h2>
<p>I&#8217;m really excited about this. I really just can&#8217;t say in words how excited I am. When I decided to accept an offer to work full-time for Adobe, one of the first &#8220;regrets&#8221; that crossed my mind was when I considered that it was highly likely that I wouldn&#8217;t be doing any more database programming (since my work involves dealing with ActionScript, and up to now there hasn&#8217;t really been any direct database access from ActionScript). So I was excited to say the least when I heard about this feature and it was decided that I&#8217;d get to work on it.</p>
<p>Suffice it to say, this has been a pretty busy time. This feature was actually slated to appear in a later release, but at the near-last minute the decision was made to get it done in time for the public beta. That meant a lot of writing and application-building in a hurry! Then two weeks and a private beta release later, a group of people including me, engineers and QEs, and other interested folks, went through a few rounds of discussions on what was missing and what we could do to make the API better. The result, which of course still isn&#8217;t finished, is what you can download today.</p>
<p>And, although she isn&#8217;t a developer and doesn&#8217;t use Apollo/AIR at all, it&#8217;s an understatement to say that my wife is glad to see this beta out the door, if only because it means I don&#8217;t have to work evenings any more (it&#8217;s been a <strong>very</strong> busy month+ =).</p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2007/06/11/adobe-air-local-sql-databases-and-my-role/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>SQL Server: Building a Mail Queue System</title>
		<link>http://probertson.com/articles/2004/09/08/sql-server-building-a-mail-queue-system/</link>
		<comments>http://probertson.com/articles/2004/09/08/sql-server-building-a-mail-queue-system/#comments</comments>
		<pubDate>Wed, 08 Sep 2004 07:15:10 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[Application Design]]></category>
		<category><![CDATA[Articles to remember]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://probertson.com/articles/2004/09/08/sql-server-building-a-mail-queue-system/</guid>
		<description><![CDATA[SQL Server: Building a Mail Queue System
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.sqlteam.com/item.asp?ItemID=5908">SQL Server: Building a Mail Queue System</a></p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2004/09/08/sql-server-building-a-mail-queue-system/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Server: Send E-Mail Without Using SQL Mail</title>
		<link>http://probertson.com/articles/2004/09/08/sql-server-send-e-mail-without-using-sql-mail/</link>
		<comments>http://probertson.com/articles/2004/09/08/sql-server-send-e-mail-without-using-sql-mail/#comments</comments>
		<pubDate>Wed, 08 Sep 2004 07:14:00 +0000</pubDate>
		<dc:creator>Paul Robertson</dc:creator>
				<category><![CDATA[Articles to remember]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://probertson.com/articles/2004/09/08/sql-server-send-e-mail-without-using-sql-mail/</guid>
		<description><![CDATA[SQL Server: Send E-Mail Without Using SQL Mail
]]></description>
			<content:encoded><![CDATA[<p><a href="http://support.microsoft.com/view/tn.asp?kb=312839">SQL Server: Send E-Mail Without Using SQL Mail</a></p>
]]></content:encoded>
			<wfw:commentRss>http://probertson.com/articles/2004/09/08/sql-server-send-e-mail-without-using-sql-mail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
