{
    "href": "/post/2005/10/26/solar-090-released/",
    "relId": "2005/10/26/solar-090-released",
    "title": "Solar 0.9.0 Released",
    "author": "pmjones",
    "markup": "html",
    "tags": [
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/solar/",
            "relId": "solar",
            "title": "Solar",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        }
    ],
    "created": "2005-10-26 15:27:06 UTC",
    "updated": [
        "2005-10-26 15:27:06 UTC"
    ],
    "html": "<p><a href=\"http://solarphp.com\" onclick=\"window.open(this.href, '_blank'); return false;\">Solar</a> is a simple object library and application repository for PHP 5.  You can view the rather extensive change log <a href=\"http://solarphp.com/channel.php?package=Solar&amp;release=0.9.0&amp;downloads\" onclick=\"window.open(this.href, '_blank'); return false;\">here</a>.</p>\n<p>This release is a major break to backwards compatibility, mostly because we now use <a href=\"http://php.net/PDO\" onclick=\"window.open(this.href, '_blank'); return false;\">PDO</a> for the SQL database API abstraction (as opposed to the homegrown solution I was using in preparation for PDO).  The distribution includes a number of <a href=\"http://solarphp.com/svn/pkg/docs/migrate/0.8.0-0.9.0/docs/\" onclick=\"window.open(this.href, '_blank'); return false;\">migration documents</a> to help users of prior versions move to the new system.</p>\n<p>I want to specifically mention one aspect of the Solar SQL system, the <a href=\"http://solarphp.com/svn/pkg/Solar/Sql/Select.php\" onclick=\"window.open(this.href, '_blank'); return false;\">Solar_Sql_Select</a> object.  This is probably not new in the PHP world, but it's the first time I've done anything like this, so I want to talk about it.</p>\n<p>One of the problems with database portability is that you can't depend on a LIMIT to work the same way across database backends; indeed, it may not even exist as such.  Different <a href=\"http://pear.php.net/DB\" onclick=\"window.open(this.href, '_blank'); return false;\">DB</a> <a href=\"http://pear.php.net/MDB2\" onclick=\"window.open(this.href, '_blank'); return false;\">abstraction</a> <a href=\"http://adodb.sourceforge.net/\" onclick=\"window.open(this.href, '_blank'); return false;\">packages</a> use different methods to support LIMIT emulation, either by rewriting the SELECT statement, or by supporting only the portions of a LIMIT clause available to the particular backend.</p>\n<p>What Solar_Sql_Select does is let you programmatically build a SELECT statement, and it keeps the clause portions separated internally.  It then combines those portions in a manner specific to the database backend driver, putting the appropriate LIMIT clauses in the right place.  Here's a quick example; let's build this SELECT statement.</p>\n<pre><code>SELECT id, date, type, name\nFROM example\nWHERE\n    date &gt;= '2005-01-01' AND\n    date &lt;= '2005-01-31' AND\n    type IN('a','b','c')\nORDER BY id\nLIMIT 10,50</code></pre>\n<p>(The LIMIT in this case is to grab 10 rows starting at row 50.)</p>\n<p>The equivalent Solar_Sql_Select code is:</p>\n<pre><code><span style=\"color: #000000\">\n\n</span><span style=\"color: #0000BB\">&lt;?php\n$select </span><span style=\"color: #007700\">= </span><span style=\"color: #0000BB\">Solar</span><span style=\"color: #007700\">::</span><span style=\"color: #0000BB\">object</span><span style=\"color: #007700\">(</span><span style=\"color: #DD0000\">\"Solar_Sql_Select\"</span><span style=\"color: #007700\">);\n\n</span><span style=\"color: #FF8000\">// the basic columns\n</span><span style=\"color: #0000BB\">$table </span><span style=\"color: #007700\">= </span><span style=\"color: #DD0000\">'example'</span><span style=\"color: #007700\">;\n</span><span style=\"color: #0000BB\">$cols </span><span style=\"color: #007700\">= array(</span><span style=\"color: #DD0000\">'id'</span><span style=\"color: #007700\">, </span><span style=\"color: #DD0000\">'date'</span><span style=\"color: #007700\">, </span><span style=\"color: #DD0000\">'type'</span><span style=\"color: #007700\">, </span><span style=\"color: #DD0000\">'name'</span><span style=\"color: #007700\">);\n\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">from</span><span style=\"color: #007700\">(</span><span style=\"color: #0000BB\">$table</span><span style=\"color: #007700\">, </span><span style=\"color: #0000BB\">$cols</span><span style=\"color: #007700\">);\n\n</span><span style=\"color: #FF8000\">// WHERE clauses for the date\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">where</span><span style=\"color: #007700\">(</span><span style=\"color: #DD0000\">'date &gt;= ?'</span><span style=\"color: #007700\">, </span><span style=\"color: #DD0000\">'2005-01-01'</span><span style=\"color: #007700\">);\n\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">where</span><span style=\"color: #007700\">(</span><span style=\"color: #DD0000\">'date &lt;= ?'</span><span style=\"color: #007700\">, </span><span style=\"color: #DD0000\">'2005-01-31'</span><span style=\"color: #007700\">);\n\n</span><span style=\"color: #FF8000\">// WHERE clause for the type\n</span><span style=\"color: #0000BB\">$types </span><span style=\"color: #007700\">= array(</span><span style=\"color: #DD0000\">'a'</span><span style=\"color: #007700\">, </span><span style=\"color: #DD0000\">'b'</span><span style=\"color: #007700\">, </span><span style=\"color: #DD0000\">'c'</span><span style=\"color: #007700\">);\n\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">where</span><span style=\"color: #007700\">(</span><span style=\"color: #DD0000\">'type IN(?)'</span><span style=\"color: #007700\">, </span><span style=\"color: #0000BB\">$types</span><span style=\"color: #007700\">);\n\n</span><span style=\"color: #FF8000\">// ORDER and LIMIT\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">order</span><span style=\"color: #007700\">(</span><span style=\"color: #DD0000\">'id'</span><span style=\"color: #007700\">);\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">limit</span><span style=\"color: #007700\">(</span><span style=\"color: #0000BB\">10</span><span style=\"color: #007700\">, </span><span style=\"color: #0000BB\">50</span><span style=\"color: #007700\">);\n\n\n</span><span style=\"color: #0000BB\">$statement </span><span style=\"color: #007700\">= </span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">fetch</span><span style=\"color: #007700\">(</span><span style=\"color: #DD0000\">'statement'</span><span style=\"color: #007700\">);\n</span><span style=\"color: #0000BB\">?&gt;</span>\n</code></pre>\n<p>Some notes:</p>\n<ul>\n<li>You can use $select-&gt;fetch() to retrieve the 'statement' as built, or actual results using 'all', 'col', 'row', 'PDOStatement', etc.</li>\n<li>In this example, quoting happens on-the-fly, and quoting an array returns a comma-separated string of the individually-quoted array values.  However, you can also use named placeholders (:start_date, :end_date, :type_list) and then use $select-&gt;bind() to bind data to those placeholders all at once.  All hail the glory of PDO.  :-)</li>\n</ul>\n<p>In the above Solar-based PHP code, when MySQL is the driver, the $statement contents will look something like the initial example.  However, when using the Microsoft SQL driver (which does not support LIMIT, only TOP), the resulting SELECT looks something like this:</p>\n<pre><code>SELECT *\nFROM (\n    SELECT TOP 10 *\n    FROM (\n        SELECT TOP 60 id, date, type, name\n        FROM example\n        WHERE\n            date &gt;= '2005-01-01' AND\n            date &lt;= '2005-01-31' AND\n            type IN('a','b','c')\n        ) AS solar_limit_rev\n        ORDER BY id DESC\n    ) AS solar_limit\nORDER BY id ASC</code></pre>\n<p>Which looks like a mess, but <a href=\"http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html\" onclick=\"window.open(this.href, '_blank'); return false;\">these guys</a> seem to think it works.  The point is that by keeping the SELECT clauses separate until you build the statement, you can manipulate the individual pieces with great precision for better portability.</p>\n<p>Another thing about Solar_Sql_Select is that paging is built in.  If you wanted to grab page 5, where pages are 10 rows each, you can do this:</p>\n<pre><code><span style=\"color: #000000\">\n</span><span style=\"color: #0000BB\">&lt;?php\n</span><span style=\"color: #FF8000\">// instead of $select-&gt;limit(10,50) ...\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">paging</span><span style=\"color: #007700\">(</span><span style=\"color: #0000BB\">10</span><span style=\"color: #007700\">); </span><span style=\"color: #FF8000\">// 10 rows per page\n\n</span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">limitPage</span><span style=\"color: #007700\">(</span><span style=\"color: #0000BB\">5</span><span style=\"color: #007700\">); </span><span style=\"color: #FF8000\">// limit to page 5\n</span><span style=\"color: #0000BB\">?&gt;</span>\n</code></pre>\n<p>Also, row-and-page counting is built in.</p>\n<pre><code><span style=\"color: #000000\">\n</span><span style=\"color: #0000BB\">&lt;?php\n\n</span><span style=\"color: #FF8000\">// instead of $select-&gt;fetch() ...\n</span><span style=\"color: #0000BB\">$total </span><span style=\"color: #007700\">= </span><span style=\"color: #0000BB\">$select</span><span style=\"color: #007700\">-&gt;</span><span style=\"color: #0000BB\">countPages</span><span style=\"color: #007700\">();\n\n</span><span style=\"color: #FF8000\">/*\n$total = array(\n    'count' =&gt; number_of_rows,\n    'pages' =&gt; number_of_pages\n);\n*/\n</span><span style=\"color: #0000BB\">?&gt;</span>\n</code></pre>\n<p>You can see more extensive Solar_Sql_Select docs <a href=\"http://solarphp.com/svn/pkg/docs/migrate/0.8.0-0.9.0/docs/solar_sql_select.txt\" onclick=\"window.open(this.href, '_blank'); return false;\">here</a> (although they are not \"real\" docs, just migration examples).</p>\n"
}
